diff --git a/src/main/java/kdotjpg/opensimplex2/areagen/OpenSimplex2S.java b/src/main/java/kdotjpg/opensimplex2/areagen/OpenSimplex2S.java index 3a17d8a..1f3c355 100644 --- a/src/main/java/kdotjpg/opensimplex2/areagen/OpenSimplex2S.java +++ b/src/main/java/kdotjpg/opensimplex2/areagen/OpenSimplex2S.java @@ -28,7 +28,7 @@ import java.util.Set; import java.util.HashSet; public class OpenSimplex2S { - + private static final int PSIZE = 2048; private static final int PMASK = 2047; @@ -40,12 +40,12 @@ public class OpenSimplex2S { perm = new short[PSIZE]; permGrad2 = new Grad2[PSIZE]; permGrad3 = new Grad3[PSIZE]; - short[] source = new short[PSIZE]; + short[] source = new short[PSIZE]; for (short i = 0; i < PSIZE; i++) source[i] = i; for (int i = PSIZE - 1; i >= 0; i--) { seed = seed * 6364136223846793005L + 1442695040888963407L; - int r = (int)((seed + 31) % (i + 1)); + int r = (int) ((seed + 31) % (i + 1)); if (r < 0) r += (i + 1); perm[i] = source[r]; @@ -54,55 +54,52 @@ public class OpenSimplex2S { source[r] = source[i]; } } - + /* * Traditional evaluators */ - + /** * 2D SuperSimplex noise, standard lattice orientation. */ public double noise2(double x, double y) { - + // Get points for A2* lattice double s = 0.366025403784439 * (x + y); double xs = x + s, ys = y + s; - + return noise2_Base(xs, ys); } - + /** - * 2D SuperSimplex noise, with Y pointing down the main diagonal. - * Might be better for a 2D sandbox style game, where Y is vertical. - * Probably slightly less optimal for heightmaps or continent maps. + * 2D SuperSimplex noise, with Y pointing down the main diagonal. Might be + * better for a 2D sandbox style game, where Y is vertical. Probably + * slightly less optimal for heightmaps or continent maps. */ public double noise2_XBeforeY(double x, double y) { - + // Skew transform and rotation baked into one. double xx = x * 0.7071067811865476; double yy = y * 1.224744871380249; - + return noise2_Base(yy + xx, yy - xx); } - + /** - * 2D SuperSimplex noise base. - * Lookup table implementation inspired by DigitalShadow. + * 2D SuperSimplex noise base. Lookup table implementation inspired by + * DigitalShadow. */ private double noise2_Base(double xs, double ys) { double value = 0; - + // Get base points and offsets int xsb = fastFloor(xs), ysb = fastFloor(ys); double xsi = xs - xsb, ysi = ys - ysb; - + // Index to point list - int a = (int)(xsi + ysi); - int index = - (a << 2) | - (int)(xsi - ysi / 2 + 1 - a / 2.0) << 3 | - (int)(ysi - xsi / 2 + 1 - a / 2.0) << 4; - + int a = (int) (xsi + ysi); + int index = (a << 2) | (int) (xsi - ysi / 2 + 1 - a / 2.0) << 3 | (int) (ysi - xsi / 2 + 1 - a / 2.0) << 4; + double ssi = (xsi + ysi) * -0.211324865405187; double xi = xsi + ssi, yi = ysi + ssi; @@ -112,98 +109,107 @@ public class OpenSimplex2S { double dx = xi + c.dx, dy = yi + c.dy; double attn = 2.0 / 3.0 - dx * dx - dy * dy; - if (attn <= 0) continue; + if (attn <= 0) + continue; int pxm = (xsb + c.xsv) & PMASK, pym = (ysb + c.ysv) & PMASK; Grad2 grad = permGrad2[perm[pxm] ^ pym]; double extrapolation = grad.dx * dx + grad.dy * dy; - + attn *= attn; value += attn * attn * extrapolation; } - + return value; } - + /** - * 3D Re-oriented 8-point BCC noise, classic orientation - * Proper substitute for what 3D SuperSimplex would be, - * in light of Forbidden Formulae. - * Use noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate. + * 3D Re-oriented 8-point BCC noise, classic orientation Proper substitute + * for what 3D SuperSimplex would be, in light of Forbidden Formulae. Use + * noise3_XYBeforeZ or noise3_XZBeforeY instead, wherever appropriate. */ public double noise3_Classic(double x, double y, double z) { - - // Re-orient the cubic lattices via rotation, to produce the expected look on cardinal planar slices. - // If texturing objects that don't tend to have cardinal plane faces, you could even remove this. + + // Re-orient the cubic lattices via rotation, to produce the expected + // look on cardinal planar slices. + // If texturing objects that don't tend to have cardinal plane faces, + // you could even remove this. // Orthonormal rotation. Not a skew transform. double r = (2.0 / 3.0) * (x + y + z); double xr = r - x, yr = r - y, zr = r - z; - + // Evaluate both lattices to form a BCC lattice. return noise3_BCC(xr, yr, zr); } - + /** * 3D Re-oriented 8-point BCC noise, with better visual isotropy in (X, Y). - * Recommended for 3D terrain and time-varied animations. - * The Z coordinate should always be the "different" coordinate in your use case. - * If Y is vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use noise3_XZBeforeY. - * If Z is vertical in world coordinates, call noise3_XYBeforeZ(x, y, Z). - * For a time varied animation, call noise3_XYBeforeZ(x, y, T). + * Recommended for 3D terrain and time-varied animations. The Z coordinate + * should always be the "different" coordinate in your use case. If Y is + * vertical in world coordinates, call noise3_XYBeforeZ(x, z, Y) or use + * noise3_XZBeforeY. If Z is vertical in world coordinates, call + * noise3_XYBeforeZ(x, y, Z). For a time varied animation, call + * noise3_XYBeforeZ(x, y, T). */ public double noise3_XYBeforeZ(double x, double y, double z) { - - // Re-orient the cubic lattices without skewing, to make X and Y triangular like 2D. + + // Re-orient the cubic lattices without skewing, to make X and Y + // triangular like 2D. // Orthonormal rotation. Not a skew transform. double xy = x + y; double s2 = xy * -0.211324865405187; double zz = z * 0.577350269189626; double xr = x + s2 - zz, yr = y + s2 - zz; double zr = xy * 0.577350269189626 + zz; - + // Evaluate both lattices to form a BCC lattice. return noise3_BCC(xr, yr, zr); } - + /** * 3D Re-oriented 8-point BCC noise, with better visual isotropy in (X, Z). - * Recommended for 3D terrain and time-varied animations. - * The Y coordinate should always be the "different" coordinate in your use case. - * If Y is vertical in world coordinates, call noise3_XZBeforeY(x, Y, z). - * If Z is vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use noise3_XYBeforeZ. - * For a time varied animation, call noise3_XZBeforeY(x, T, y) or use noise3_XYBeforeZ. + * Recommended for 3D terrain and time-varied animations. The Y coordinate + * should always be the "different" coordinate in your use case. If Y is + * vertical in world coordinates, call noise3_XZBeforeY(x, Y, z). If Z is + * vertical in world coordinates, call noise3_XZBeforeY(x, Z, y) or use + * noise3_XYBeforeZ. For a time varied animation, call noise3_XZBeforeY(x, + * T, y) or use noise3_XYBeforeZ. */ public double noise3_XZBeforeY(double x, double y, double z) { - - // Re-orient the cubic lattices without skewing, to make X and Z triangular like 2D. + + // Re-orient the cubic lattices without skewing, to make X and Z + // triangular like 2D. // Orthonormal rotation. Not a skew transform. double xz = x + z; double s2 = xz * -0.211324865405187; double yy = y * 0.577350269189626; - double xr = x + s2 - yy; double zr = z + s2 - yy; + double xr = x + s2 - yy; + double zr = z + s2 - yy; double yr = xz * 0.577350269189626 + yy; - + // Evaluate both lattices to form a BCC lattice. return noise3_BCC(xr, yr, zr); } - + /** - * Generate overlapping cubic lattices for 3D Re-oriented BCC noise. - * Lookup table implementation inspired by DigitalShadow. - * It was actually faster to narrow down the points in the loop itself, - * than to build up the index with enough info to isolate 8 points. + * Generate overlapping cubic lattices for 3D Re-oriented BCC noise. Lookup + * table implementation inspired by DigitalShadow. It was actually faster to + * narrow down the points in the loop itself, than to build up the index + * with enough info to isolate 8 points. */ private double noise3_BCC(double xr, double yr, double zr) { - + // Get base and offsets inside cube of first lattice. int xrb = fastFloor(xr), yrb = fastFloor(yr), zrb = fastFloor(zr); double xri = xr - xrb, yri = yr - yrb, zri = zr - zrb; - - // Identify which octant of the cube we're in. This determines which cell - // in the other cubic lattice we're in, and also narrows down one point on each. - int xht = (int)(xri + 0.5), yht = (int)(yri + 0.5), zht = (int)(zri + 0.5); + + // Identify which octant of the cube we're in. This determines which + // cell + // in the other cubic lattice we're in, and also narrows down one point + // on each. + int xht = (int) (xri + 0.5), yht = (int) (yri + 0.5), zht = (int) (zri + 0.5); int index = (xht << 0) | (yht << 1) | (zht << 2); - + // Point contributions double value = 0; LatticePoint3D c = LOOKUP_3D[index]; @@ -216,7 +222,7 @@ public class OpenSimplex2S { int pxm = (xrb + c.xrv) & PMASK, pym = (yrb + c.yrv) & PMASK, pzm = (zrb + c.zrv) & PMASK; Grad3 grad = permGrad3[perm[perm[pxm] ^ pym] ^ pzm]; double extrapolation = grad.dx * dxr + grad.dy * dyr + grad.dz * dzr; - + attn *= attn; value += attn * attn * extrapolation; c = c.nextOnSuccess; @@ -224,122 +230,138 @@ public class OpenSimplex2S { } return value; } - + /* * Area Generators */ - + /** - * Generate the 2D noise over a large area. - * Propagates by flood-fill instead of iterating over a range. - * Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel. + * Generate the 2D noise over a large area. Propagates by flood-fill instead + * of iterating over a range. Results may occasionally slightly exceed [-1, + * 1] due to the grid-snapped pre-generated kernel. */ public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0) { int height = buffer.length; int width = buffer[0].length; generate2(context, buffer, x0, y0, width, height, 0, 0); } - + /** - * Generate the 2D noise over a large area. - * Propagates by flood-fill instead of iterating over a range. - * Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel. + * Generate the 2D noise over a large area. Propagates by flood-fill instead + * of iterating over a range. Results may occasionally slightly exceed [-1, + * 1] due to the grid-snapped pre-generated kernel. */ - public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0, int width, int height, int skipX, int skipY) { + public void generate2(GenerateContext2D context, double[][] buffer, int x0, int y0, int width, int height, + int skipX, int skipY) { Queue queue = new LinkedList(); Set seen = new HashSet(); - + int scaledRadiusX = context.scaledRadiusX; int scaledRadiusY = context.scaledRadiusY; double[][] kernel = context.kernel; int x0Skipped = x0 + skipX, y0Skipped = y0 + skipY; - + // It seems that it's better for performance, to create a local copy. // - Slightly faster than generating the kernel here. // - Much faster than referencing it directly from the context object. // - Much faster than computing the kernel equation every time. // You can remove these lines if you find it's the opposite for you. // You'll have to double the bounds again in GenerateContext2D - kernel = new double[scaledRadiusY * 2][/*scaledRadiusX * 2*/]; + kernel = new double[scaledRadiusY * 2][/* scaledRadiusX * 2 */]; for (int yy = 0; yy < scaledRadiusY; yy++) { kernel[2 * scaledRadiusY - yy - 1] = kernel[yy] = (double[]) context.kernel[yy].clone(); } - + // Get started with one point/vertex. - // For some lattices, you might need to try a handful of points in the cell, - // or flip a couple of coordinates, to guarantee it or a neighbor contributes. + // For some lattices, you might need to try a handful of points in the + // cell, + // or flip a couple of coordinates, to guarantee it or a neighbor + // contributes. // For An* lattices, the base coordinate seems fine. - double x0f = x0Skipped * context.xFrequency; double y0f = y0Skipped * context.yFrequency; + double x0f = x0Skipped * context.xFrequency; + double y0f = y0Skipped * context.yFrequency; double x0s = context.orientation.s00 * x0f + context.orientation.s01 * y0f; double y0s = context.orientation.s10 * x0f + context.orientation.s11 * y0f; int x0sb = fastFloor(x0s), y0sb = fastFloor(y0s); AreaGenLatticePoint2D firstPoint = new AreaGenLatticePoint2D(context, x0sb, y0sb); queue.add(firstPoint); seen.add(firstPoint); - + while (!queue.isEmpty()) { AreaGenLatticePoint2D point = queue.remove(); int destPointX = point.destPointX; int destPointY = point.destPointY; - + // Prepare gradient vector int pxm = point.xsv & PMASK, pym = point.ysv & PMASK; Grad2 grad = context.orientation.gradients[perm[perm[pxm] ^ pym]]; double gx = grad.dx * context.xFrequency; double gy = grad.dy * context.yFrequency; - double gOff = 0.5 * (gx + gy); // to correct for (0.5, 0.5)-offset kernel - + double gOff = 0.5 * (gx + gy); // to correct for (0.5, 0.5)-offset + // kernel + // Contribution kernel bounds - int yy0 = destPointY - scaledRadiusY; if (yy0 < y0Skipped) yy0 = y0Skipped; - int yy1 = destPointY + scaledRadiusY; if (yy1 > y0 + height) yy1 = y0 + height; - + int yy0 = destPointY - scaledRadiusY; + if (yy0 < y0Skipped) + yy0 = y0Skipped; + int yy1 = destPointY + scaledRadiusY; + if (yy1 > y0 + height) + yy1 = y0 + height; + // For each row of the contribution circle, for (int yy = yy0; yy < yy1; yy++) { int dy = yy - destPointY; int ky = dy + scaledRadiusY; - + // Set up bounds so we only loop over what we need to int thisScaledRadiusX = context.kernelBounds[ky]; - int xx0 = destPointX - thisScaledRadiusX; if (xx0 < x0Skipped) xx0 = x0Skipped; - int xx1 = destPointX + thisScaledRadiusX; if (xx1 > x0 + width) xx1 = x0 + width; - + int xx0 = destPointX - thisScaledRadiusX; + if (xx0 < x0Skipped) + xx0 = x0Skipped; + int xx1 = destPointX + thisScaledRadiusX; + if (xx1 > x0 + width) + xx1 = x0 + width; + // For each point on that row for (int xx = xx0; xx < xx1; xx++) { int dx = xx - destPointX; int kx = dx + scaledRadiusX; - - // gOff accounts for our choice to offset the pre-generated kernel by (0.5, 0.5) to avoid the zero center. - // I found almost no difference in performance using gOff vs not (under 1ns diff per value on my system) + + // gOff accounts for our choice to offset the pre-generated + // kernel by (0.5, 0.5) to avoid the zero center. + // I found almost no difference in performance using gOff vs + // not (under 1ns diff per value on my system) double extrapolation = gx * dx + gy * dy + gOff; buffer[yy - y0][xx - x0] += kernel[ky][kx] * extrapolation; - + } } - + // For each neighbor of the point for (int i = 0; i < NEIGHBOR_MAP_2D.length; i++) { - AreaGenLatticePoint2D neighbor = new AreaGenLatticePoint2D(context, - point.xsv + NEIGHBOR_MAP_2D[i][0], point.ysv + NEIGHBOR_MAP_2D[i][1]); - + AreaGenLatticePoint2D neighbor = new AreaGenLatticePoint2D(context, point.xsv + NEIGHBOR_MAP_2D[i][0], + point.ysv + NEIGHBOR_MAP_2D[i][1]); + // If it's in range of the buffer region and not seen before - if (neighbor.destPointX + scaledRadiusX >= x0Skipped && neighbor.destPointX - scaledRadiusX <= x0 + width - 1 - && neighbor.destPointY + scaledRadiusY >= y0Skipped && neighbor.destPointY - scaledRadiusY <= y0 + height - 1 - && !seen.contains(neighbor)) { - + if (neighbor.destPointX + scaledRadiusX >= x0Skipped + && neighbor.destPointX - scaledRadiusX <= x0 + width - 1 + && neighbor.destPointY + scaledRadiusY >= y0Skipped + && neighbor.destPointY - scaledRadiusY <= y0 + height - 1 && !seen.contains(neighbor)) { + // Add it to the queue so we can process it at some point queue.add(neighbor); - + // Add it to the set so we don't add it to the queue again seen.add(neighbor); } } } } - + /** - * Generate the 3D noise over a large area/volume. - * Propagates by flood-fill instead of iterating over a range. - * Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel. + * Generate the 3D noise over a large area/volume. Propagates by flood-fill + * instead of iterating over a range. Results may occasionally slightly + * exceed [-1, 1] due to the grid-snapped pre-generated kernel. */ public void generate3(GenerateContext3D context, double[][][] buffer, int x0, int y0, int z0) { int depth = buffer.length; @@ -347,121 +369,142 @@ public class OpenSimplex2S { int width = buffer[0][0].length; generate3(context, buffer, x0, y0, z0, width, height, depth, 0, 0, 0); } - + /** - * Generate the 3D noise over a large area/volume. - * Propagates by flood-fill instead of iterating over a range. - * Results may occasionally slightly exceed [-1, 1] due to the grid-snapped pre-generated kernel. + * Generate the 3D noise over a large area/volume. Propagates by flood-fill + * instead of iterating over a range. Results may occasionally slightly + * exceed [-1, 1] due to the grid-snapped pre-generated kernel. */ - public void generate3(GenerateContext3D context, double[][][] buffer, int x0, int y0, int z0, int width, int height, int depth, int skipX, int skipY, int skipZ) { + public void generate3(GenerateContext3D context, double[][][] buffer, int x0, int y0, int z0, int width, int height, + int depth, int skipX, int skipY, int skipZ) { Queue queue = new LinkedList(); Set seen = new HashSet(); - + int scaledRadiusX = context.scaledRadiusX; int scaledRadiusY = context.scaledRadiusY; int scaledRadiusZ = context.scaledRadiusZ; double[][][] kernel = context.kernel; int x0Skipped = x0 + skipX, y0Skipped = y0 + skipY, z0Skipped = z0 + skipZ; - + // Quaternion multiplication for rotation. // https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/ - double qx = context.orientation.qx, qy = context.orientation.qy, qz = context.orientation.qz, qw = context.orientation.qw; - double x0f = x0Skipped * context.xFrequency, y0f = y0Skipped * context.yFrequency, z0f = z0Skipped * context.zFrequency; + double qx = context.orientation.qx, qy = context.orientation.qy, qz = context.orientation.qz, + qw = context.orientation.qw; + double x0f = x0Skipped * context.xFrequency, y0f = y0Skipped * context.yFrequency, + z0f = z0Skipped * context.zFrequency; double tx = 2 * (qy * z0f - qz * y0f); double ty = 2 * (qz * x0f - qx * z0f); double tz = 2 * (qx * y0f - qy * x0f); double x0r = x0f + qw * tx + (qy * tz - qz * ty); double y0r = y0f + qw * ty + (qz * tx - qx * tz); double z0r = z0f + qw * tz + (qx * ty - qy * tx); - + int x0rb = fastFloor(x0r), y0rb = fastFloor(y0r), z0rb = fastFloor(z0r); - + AreaGenLatticePoint3D firstPoint = new AreaGenLatticePoint3D(context, x0rb, y0rb, z0rb, 0); queue.add(firstPoint); seen.add(firstPoint); - + while (!queue.isEmpty()) { AreaGenLatticePoint3D point = queue.remove(); int destPointX = point.destPointX; int destPointY = point.destPointY; int destPointZ = point.destPointZ; - + // Prepare gradient vector int pxm = point.xsv & PMASK, pym = point.ysv & PMASK, pzm = point.zsv & PMASK; Grad3 grad = context.orientation.gradients[perm[perm[perm[pxm] ^ pym] ^ pzm]]; double gx = grad.dx * context.xFrequency; double gy = grad.dy * context.yFrequency; double gz = grad.dz * context.zFrequency; - double gOff = 0.5 * (gx + gy + gz); // to correct for (0.5, 0.5, 0.5)-offset kernel - + double gOff = 0.5 * (gx + gy + gz); // to correct for (0.5, 0.5, + // 0.5)-offset kernel + // Contribution kernel bounds. - int zz0 = destPointZ - scaledRadiusZ; if (zz0 < z0Skipped) zz0 = z0Skipped; - int zz1 = destPointZ + scaledRadiusZ; if (zz1 > z0 + depth) zz1 = z0 + depth; - + int zz0 = destPointZ - scaledRadiusZ; + if (zz0 < z0Skipped) + zz0 = z0Skipped; + int zz1 = destPointZ + scaledRadiusZ; + if (zz1 > z0 + depth) + zz1 = z0 + depth; + // For each x/y slice of the contribution sphere, for (int zz = zz0; zz < zz1; zz++) { int dz = zz - destPointZ; int kz = dz + scaledRadiusZ; - + // Set up bounds so we only loop over what we need to int thisScaledRadiusY = context.kernelBoundsY[kz]; - int yy0 = destPointY - thisScaledRadiusY; if (yy0 < y0Skipped) yy0 = y0Skipped; - int yy1 = destPointY + thisScaledRadiusY; if (yy1 > y0 + height) yy1 = y0 + height; - + int yy0 = destPointY - thisScaledRadiusY; + if (yy0 < y0Skipped) + yy0 = y0Skipped; + int yy1 = destPointY + thisScaledRadiusY; + if (yy1 > y0 + height) + yy1 = y0 + height; + // For each row of the contribution circle, for (int yy = yy0; yy < yy1; yy++) { int dy = yy - destPointY; int ky = dy + scaledRadiusY; - + // Set up bounds so we only loop over what we need to int thisScaledRadiusX = context.kernelBoundsX[kz][ky]; - int xx0 = destPointX - thisScaledRadiusX; if (xx0 < x0Skipped) xx0 = x0Skipped; - int xx1 = destPointX + thisScaledRadiusX; if (xx1 > x0 + width) xx1 = x0 + width; - + int xx0 = destPointX - thisScaledRadiusX; + if (xx0 < x0Skipped) + xx0 = x0Skipped; + int xx1 = destPointX + thisScaledRadiusX; + if (xx1 > x0 + width) + xx1 = x0 + width; + // For each point on that row for (int xx = xx0; xx < xx1; xx++) { int dx = xx - destPointX; int kx = dx + scaledRadiusX; - - // gOff accounts for our choice to offset the pre-generated kernel by (0.5, 0.5, 0.5) to avoid the zero center. + + // gOff accounts for our choice to offset the + // pre-generated kernel by (0.5, 0.5, 0.5) to avoid the + // zero center. double extrapolation = gx * dx + gy * dy + gz * dz + gOff; buffer[zz - z0][yy - y0][xx - x0] += kernel[kz][ky][kx] * extrapolation; - + } } } - + // For each neighbor of the point for (int i = 0; i < NEIGHBOR_MAP_3D[0].length; i++) { int l = point.lattice; AreaGenLatticePoint3D neighbor = new AreaGenLatticePoint3D(context, - point.xsv + NEIGHBOR_MAP_3D[l][i][0], point.ysv + NEIGHBOR_MAP_3D[l][i][1], point.zsv + NEIGHBOR_MAP_3D[l][i][2], 1 ^ l); - + point.xsv + NEIGHBOR_MAP_3D[l][i][0], point.ysv + NEIGHBOR_MAP_3D[l][i][1], + point.zsv + NEIGHBOR_MAP_3D[l][i][2], 1 ^ l); + // If it's in range of the buffer region and not seen before - if (neighbor.destPointX + scaledRadiusX >= x0Skipped && neighbor.destPointX - scaledRadiusX <= x0 + width - 1 - && neighbor.destPointY + scaledRadiusY >= y0Skipped && neighbor.destPointY - scaledRadiusY <= y0 + height - 1 - && neighbor.destPointZ + scaledRadiusZ >= z0Skipped && neighbor.destPointZ - scaledRadiusZ <= z0 + depth - 1 - && !seen.contains(neighbor)) { - + if (neighbor.destPointX + scaledRadiusX >= x0Skipped + && neighbor.destPointX - scaledRadiusX <= x0 + width - 1 + && neighbor.destPointY + scaledRadiusY >= y0Skipped + && neighbor.destPointY - scaledRadiusY <= y0 + height - 1 + && neighbor.destPointZ + scaledRadiusZ >= z0Skipped + && neighbor.destPointZ - scaledRadiusZ <= z0 + depth - 1 && !seen.contains(neighbor)) { + // Add it to the queue so we can process it at some point queue.add(neighbor); - + // Add it to the set so we don't add it to the queue again seen.add(neighbor); } } } } - + /* * Utility */ - + private static int fastFloor(double x) { - int xi = (int)x; + int xi = (int) x; return x < xi ? xi - 1 : xi; } - + /* * Definitions */ @@ -471,186 +514,242 @@ public class OpenSimplex2S { static { LOOKUP_2D = new LatticePoint2D[8 * 4]; LOOKUP_3D = new LatticePoint3D[8]; - + for (int i = 0; i < 8; i++) { int i1, j1, i2, j2; if ((i & 1) == 0) { - if ((i & 2) == 0) { i1 = -1; j1 = 0; } else { i1 = 1; j1 = 0; } - if ((i & 4) == 0) { i2 = 0; j2 = -1; } else { i2 = 0; j2 = 1; } + if ((i & 2) == 0) { + i1 = -1; + j1 = 0; + } else { + i1 = 1; + j1 = 0; + } + if ((i & 4) == 0) { + i2 = 0; + j2 = -1; + } else { + i2 = 0; + j2 = 1; + } } else { - if ((i & 2) != 0) { i1 = 2; j1 = 1; } else { i1 = 0; j1 = 1; } - if ((i & 4) != 0) { i2 = 1; j2 = 2; } else { i2 = 1; j2 = 0; } + if ((i & 2) != 0) { + i1 = 2; + j1 = 1; + } else { + i1 = 0; + j1 = 1; + } + if ((i & 4) != 0) { + i2 = 1; + j2 = 2; + } else { + i2 = 1; + j2 = 0; + } } LOOKUP_2D[i * 4 + 0] = new LatticePoint2D(0, 0); LOOKUP_2D[i * 4 + 1] = new LatticePoint2D(1, 1); LOOKUP_2D[i * 4 + 2] = new LatticePoint2D(i1, j1); LOOKUP_2D[i * 4 + 3] = new LatticePoint2D(i2, j2); } - + for (int i = 0; i < 8; i++) { int i1, j1, k1, i2, j2, k2; - i1 = (i >> 0) & 1; j1 = (i >> 1) & 1; k1 = (i >> 2) & 1; - i2 = i1 ^ 1; j2 = j1 ^ 1; k2 = k1 ^ 1; - - // The two points within this octant, one from each of the two cubic half-lattices. + i1 = (i >> 0) & 1; + j1 = (i >> 1) & 1; + k1 = (i >> 2) & 1; + i2 = i1 ^ 1; + j2 = j1 ^ 1; + k2 = k1 ^ 1; + + // The two points within this octant, one from each of the two cubic + // half-lattices. LatticePoint3D c0 = new LatticePoint3D(i1, j1, k1, 0); LatticePoint3D c1 = new LatticePoint3D(i1 + i2, j1 + j2, k1 + k2, 1); - + // (1, 0, 0) vs (0, 1, 1) away from octant. LatticePoint3D c2 = new LatticePoint3D(i1 ^ 1, j1, k1, 0); LatticePoint3D c3 = new LatticePoint3D(i1, j1 ^ 1, k1 ^ 1, 0); - + // (1, 0, 0) vs (0, 1, 1) away from octant, on second half-lattice. LatticePoint3D c4 = new LatticePoint3D(i1 + (i2 ^ 1), j1 + j2, k1 + k2, 1); LatticePoint3D c5 = new LatticePoint3D(i1 + i2, j1 + (j2 ^ 1), k1 + (k2 ^ 1), 1); - + // (0, 1, 0) vs (1, 0, 1) away from octant. LatticePoint3D c6 = new LatticePoint3D(i1, j1 ^ 1, k1, 0); LatticePoint3D c7 = new LatticePoint3D(i1 ^ 1, j1, k1 ^ 1, 0); - + // (0, 1, 0) vs (1, 0, 1) away from octant, on second half-lattice. LatticePoint3D c8 = new LatticePoint3D(i1 + i2, j1 + (j2 ^ 1), k1 + k2, 1); LatticePoint3D c9 = new LatticePoint3D(i1 + (i2 ^ 1), j1 + j2, k1 + (k2 ^ 1), 1); - + // (0, 0, 1) vs (1, 1, 0) away from octant. LatticePoint3D cA = new LatticePoint3D(i1, j1, k1 ^ 1, 0); LatticePoint3D cB = new LatticePoint3D(i1 ^ 1, j1 ^ 1, k1, 0); - + // (0, 0, 1) vs (1, 1, 0) away from octant, on second half-lattice. LatticePoint3D cC = new LatticePoint3D(i1 + i2, j1 + j2, k1 + (k2 ^ 1), 1); LatticePoint3D cD = new LatticePoint3D(i1 + (i2 ^ 1), j1 + (j2 ^ 1), k1 + k2, 1); - + // First two points are guaranteed. c0.nextOnFailure = c0.nextOnSuccess = c1; c1.nextOnFailure = c1.nextOnSuccess = c2; - + // If c2 is in range, then we know c3 and c4 are not. - c2.nextOnFailure = c3; c2.nextOnSuccess = c5; - c3.nextOnFailure = c4; c3.nextOnSuccess = c4; - + c2.nextOnFailure = c3; + c2.nextOnSuccess = c5; + c3.nextOnFailure = c4; + c3.nextOnSuccess = c4; + // If c4 is in range, then we know c5 is not. - c4.nextOnFailure = c5; c4.nextOnSuccess = c6; + c4.nextOnFailure = c5; + c4.nextOnSuccess = c6; c5.nextOnFailure = c5.nextOnSuccess = c6; - + // If c6 is in range, then we know c7 and c8 are not. - c6.nextOnFailure = c7; c6.nextOnSuccess = c9; - c7.nextOnFailure = c8; c7.nextOnSuccess = c8; - + c6.nextOnFailure = c7; + c6.nextOnSuccess = c9; + c7.nextOnFailure = c8; + c7.nextOnSuccess = c8; + // If c8 is in range, then we know c9 is not. - c8.nextOnFailure = c9; c8.nextOnSuccess = cA; + c8.nextOnFailure = c9; + c8.nextOnSuccess = cA; c9.nextOnFailure = c9.nextOnSuccess = cA; - + // If cA is in range, then we know cB and cC are not. - cA.nextOnFailure = cB; cA.nextOnSuccess = cD; - cB.nextOnFailure = cC; cB.nextOnSuccess = cC; - + cA.nextOnFailure = cB; + cA.nextOnSuccess = cD; + cB.nextOnFailure = cC; + cB.nextOnSuccess = cC; + // If cC is in range, then we know cD is not. - cC.nextOnFailure = cD; cC.nextOnSuccess = null; + cC.nextOnFailure = cD; + cC.nextOnSuccess = null; cD.nextOnFailure = cD.nextOnSuccess = null; - + LOOKUP_3D[i] = c0; - + } } - + // Hexagon surrounding each vertex. - private static final int[][] NEIGHBOR_MAP_2D = { - { 1, 0 }, { 1, 1 }, { 0, 1 }, { 0, -1 }, { -1, -1 }, { -1, 0 } - }; - + private static final int[][] NEIGHBOR_MAP_2D = { { 1, 0 }, { 1, 1 }, { 0, 1 }, { 0, -1 }, { -1, -1 }, { -1, 0 } }; + // Cube surrounding each vertex. // Alternates between half-lattices. private static final int[][][] NEIGHBOR_MAP_3D = { - { - { 1024, 1024, 1024 }, { 1025, 1024, 1024 }, { 1024, 1025, 1024 }, { 1025, 1025, 1024 }, - { 1024, 1024, 1025 }, { 1025, 1024, 1025 }, { 1024, 1025, 1025 }, { 1025, 1025, 1025 } - }, - { - { -1024, -1024, -1024 }, { -1025, -1024, 1024 }, { -1024, -1025, -1024 }, { -1025, -1025, -1024 }, - { -1024, -1024, -1025 }, { -1025, -1024, -1025 }, { -1024, -1025, -1025 }, { -1025, -1025, 1025 } - }, - }; - + { { 1024, 1024, 1024 }, { 1025, 1024, 1024 }, { 1024, 1025, 1024 }, { 1025, 1025, 1024 }, + { 1024, 1024, 1025 }, { 1025, 1024, 1025 }, { 1024, 1025, 1025 }, { 1025, 1025, 1025 } }, + { { -1024, -1024, -1024 }, { -1025, -1024, 1024 }, { -1024, -1025, -1024 }, { -1025, -1025, -1024 }, + { -1024, -1024, -1025 }, { -1025, -1024, -1025 }, { -1024, -1025, -1025 }, + { -1025, -1025, 1025 } }, }; + private static class LatticePoint2D { int xsv, ysv; double dx, dy; + public LatticePoint2D(int xsv, int ysv) { - this.xsv = xsv; this.ysv = ysv; + this.xsv = xsv; + this.ysv = ysv; double ssv = (xsv + ysv) * -0.211324865405187; this.dx = -xsv - ssv; this.dy = -ysv - ssv; } } - + private static class LatticePoint3D { public double dxr, dyr, dzr; public int xrv, yrv, zrv; LatticePoint3D nextOnFailure, nextOnSuccess; + public LatticePoint3D(int xrv, int yrv, int zrv, int lattice) { - this.dxr = -xrv + lattice * 0.5; this.dyr = -yrv + lattice * 0.5; this.dzr = -zrv + lattice * 0.5; - this.xrv = xrv + lattice * 1024; this.yrv = yrv + lattice * 1024; this.zrv = zrv + lattice * 1024; + this.dxr = -xrv + lattice * 0.5; + this.dyr = -yrv + lattice * 0.5; + this.dzr = -zrv + lattice * 0.5; + this.xrv = xrv + lattice * 1024; + this.yrv = yrv + lattice * 1024; + this.zrv = zrv + lattice * 1024; } } - + private static class AreaGenLatticePoint2D { int xsv, ysv; int destPointX, destPointY; + public AreaGenLatticePoint2D(GenerateContext2D context, int xsv, int ysv) { - this.xsv = xsv; this.ysv = ysv; - - //Matrix multiplication for inverse rotation. Simplex skew transforms have always been shorthand for matrices. - this.destPointX = (int)Math.ceil((context.orientation.t00 * xsv + context.orientation.t01 * ysv) * context.xFrequencyInverse); - this.destPointY = (int)Math.ceil((context.orientation.t10 * xsv + context.orientation.t11 * ysv) * context.yFrequencyInverse); + this.xsv = xsv; + this.ysv = ysv; + + // Matrix multiplication for inverse rotation. Simplex skew + // transforms have always been shorthand for matrices. + this.destPointX = (int) Math + .ceil((context.orientation.t00 * xsv + context.orientation.t01 * ysv) * context.xFrequencyInverse); + this.destPointY = (int) Math + .ceil((context.orientation.t10 * xsv + context.orientation.t11 * ysv) * context.yFrequencyInverse); } + @Override public int hashCode() { return xsv * 7841 + ysv; } + @Override public boolean equals(Object obj) { - if (!(obj instanceof AreaGenLatticePoint2D)) return false; + if (!(obj instanceof AreaGenLatticePoint2D)) + return false; AreaGenLatticePoint2D other = (AreaGenLatticePoint2D) obj; return (other.xsv == this.xsv && other.ysv == this.ysv); } } - + private static class AreaGenLatticePoint3D { int xsv, ysv, zsv, lattice; int destPointX, destPointY, destPointZ; + public AreaGenLatticePoint3D(GenerateContext3D context, int xsv, int ysv, int zsv, int lattice) { - this.xsv = xsv; this.ysv = ysv; this.zsv = zsv; this.lattice = lattice; + this.xsv = xsv; + this.ysv = ysv; + this.zsv = zsv; + this.lattice = lattice; double xr = (xsv - lattice * 1024.5); double yr = (ysv - lattice * 1024.5); double zr = (zsv - lattice * 1024.5); - + // Quaternion multiplication for inverse rotation. // https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/ - double qx = -context.orientation.qx, qy = -context.orientation.qy, qz = -context.orientation.qz, qw = context.orientation.qw; + double qx = -context.orientation.qx, qy = -context.orientation.qy, qz = -context.orientation.qz, + qw = context.orientation.qw; double tx = 2 * (qy * zr - qz * yr); double ty = 2 * (qz * xr - qx * zr); double tz = 2 * (qx * yr - qy * xr); double xrr = xr + qw * tx + (qy * tz - qz * ty); double yrr = yr + qw * ty + (qz * tx - qx * tz); double zrr = zr + qw * tz + (qx * ty - qy * tx); - - this.destPointX = (int)Math.ceil(xrr * context.xFrequencyInverse); - this.destPointY = (int)Math.ceil(yrr * context.yFrequencyInverse); - this.destPointZ = (int)Math.ceil(zrr * context.zFrequencyInverse); + + this.destPointX = (int) Math.ceil(xrr * context.xFrequencyInverse); + this.destPointY = (int) Math.ceil(yrr * context.yFrequencyInverse); + this.destPointZ = (int) Math.ceil(zrr * context.zFrequencyInverse); } + @Override public int hashCode() { return xsv * 2122193 + ysv * 2053 + zsv * 2 + lattice; } + @Override public boolean equals(Object obj) { - if (!(obj instanceof AreaGenLatticePoint3D)) return false; + if (!(obj instanceof AreaGenLatticePoint3D)) + return false; AreaGenLatticePoint3D other = (AreaGenLatticePoint3D) obj; - return (other.xsv == this.xsv && other.ysv == this.ysv && other.zsv == this.zsv && other.lattice == this.lattice); + return (other.xsv == this.xsv && other.ysv == this.ysv && other.zsv == this.zsv + && other.lattice == this.lattice); } } - + public static class GenerateContext2D { - + double xFrequency; double yFrequency; double xFrequencyInverse; @@ -660,37 +759,37 @@ public class OpenSimplex2S { double[][] kernel; int[] kernelBounds; LatticeOrientation2D orientation; - - public GenerateContext2D(LatticeOrientation2D orientation, double xFrequency, double yFrequency, double amplitude) { - + + public GenerateContext2D(LatticeOrientation2D orientation, double xFrequency, double yFrequency, + double amplitude) { + // These will be used by every call to generate this.orientation = orientation; this.xFrequency = xFrequency; this.yFrequency = yFrequency; this.xFrequencyInverse = 1.0 / xFrequency; this.yFrequencyInverse = 1.0 / yFrequency; - + double preciseScaledRadiusX = Math.sqrt(2.0 / 3.0) * xFrequencyInverse; double preciseScaledRadiusY = Math.sqrt(2.0 / 3.0) * yFrequencyInverse; - + // 0.25 because we offset center by 0.5 - this.scaledRadiusX = (int)Math.ceil(preciseScaledRadiusX + 0.25); - this.scaledRadiusY = (int)Math.ceil(preciseScaledRadiusY + 0.25); - + this.scaledRadiusX = (int) Math.ceil(preciseScaledRadiusX + 0.25); + this.scaledRadiusY = (int) Math.ceil(preciseScaledRadiusY + 0.25); + // So will these - kernel = new double[scaledRadiusY/* * 2*/][]; + kernel = new double[scaledRadiusY/* * 2 */][]; kernelBounds = new int[scaledRadiusY * 2]; for (int yy = 0; yy < scaledRadiusY * 2; yy++) { - + // Pre-generate boundary of circle - kernelBounds[yy] = (int)Math.ceil( - Math.sqrt(1.0 - - (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY) - ) * scaledRadiusX); - + kernelBounds[yy] = (int) Math.ceil(Math.sqrt( + 1.0 - (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY)) + * scaledRadiusX); + if (yy < scaledRadiusY) { kernel[yy] = new double[scaledRadiusX * 2]; - + // Pre-generate kernel for (int xx = 0; xx < scaledRadiusX * 2; xx++) { double dx = (xx + 0.5 - scaledRadiusX) * xFrequency; @@ -703,13 +802,13 @@ public class OpenSimplex2S { kernel[yy][xx] = 0.0; } } - } /* else kernel[yy] = kernel[2 * scaledRadiusY - yy - 1];*/ + } /* else kernel[yy] = kernel[2 * scaledRadiusY - yy - 1]; */ } } } - + public static class GenerateContext3D { - + double xFrequency; double yFrequency; double zFrequency; @@ -723,9 +822,10 @@ public class OpenSimplex2S { int[] kernelBoundsY; int[][] kernelBoundsX; LatticeOrientation3D orientation; - - public GenerateContext3D(LatticeOrientation3D orientation, double xFrequency, double yFrequency, double zFrequency, double amplitude) { - + + public GenerateContext3D(LatticeOrientation3D orientation, double xFrequency, double yFrequency, + double zFrequency, double amplitude) { + // These will be used by every call to generate this.orientation = orientation; this.xFrequency = xFrequency; @@ -734,27 +834,27 @@ public class OpenSimplex2S { this.xFrequencyInverse = 1.0 / xFrequency; this.yFrequencyInverse = 1.0 / yFrequency; this.zFrequencyInverse = 1.0 / zFrequency; - + double preciseScaledRadiusX = Math.sqrt(0.75) * xFrequencyInverse; double preciseScaledRadiusY = Math.sqrt(0.75) * yFrequencyInverse; double preciseScaledRadiusZ = Math.sqrt(0.75) * zFrequencyInverse; - + // 0.25 because we offset center by 0.5 - this.scaledRadiusX = (int)Math.ceil(preciseScaledRadiusX + 0.25); - this.scaledRadiusY = (int)Math.ceil(preciseScaledRadiusY + 0.25); - this.scaledRadiusZ = (int)Math.ceil(preciseScaledRadiusZ + 0.25); - + this.scaledRadiusX = (int) Math.ceil(preciseScaledRadiusX + 0.25); + this.scaledRadiusY = (int) Math.ceil(preciseScaledRadiusY + 0.25); + this.scaledRadiusZ = (int) Math.ceil(preciseScaledRadiusZ + 0.25); + // So will these kernel = new double[scaledRadiusZ * 2][][]; kernelBoundsY = new int[scaledRadiusZ * 2]; kernelBoundsX = new int[scaledRadiusZ * 2][]; for (int zz = 0; zz < scaledRadiusZ * 2; zz++) { - + // Pre-generate boundary of sphere - kernelBoundsY[zz] = (int)Math.ceil( - Math.sqrt(1.0 - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) - / (scaledRadiusZ * scaledRadiusZ)) * scaledRadiusY); - + kernelBoundsY[zz] = (int) Math.ceil(Math.sqrt( + 1.0 - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) / (scaledRadiusZ * scaledRadiusZ)) + * scaledRadiusY); + if (zz < scaledRadiusZ) { kernel[zz] = new double[scaledRadiusY * 2][]; kernelBoundsX[zz] = new int[scaledRadiusY * 2]; @@ -762,20 +862,21 @@ public class OpenSimplex2S { kernel[zz] = kernel[2 * scaledRadiusZ - zz - 1]; kernelBoundsX[zz] = kernelBoundsX[2 * scaledRadiusZ - zz - 1]; } - + if (zz < scaledRadiusZ) { for (int yy = 0; yy < scaledRadiusY * 2; yy++) { - + // Pre-generate boundary of sphere - kernelBoundsX[zz][yy] = (int)Math.ceil( - Math.sqrt(1.0 - - (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) / (scaledRadiusY * scaledRadiusY) - - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) / (scaledRadiusZ * scaledRadiusZ) - ) * scaledRadiusX); - + kernelBoundsX[zz][yy] = (int) Math.ceil(Math.sqrt(1.0 + - (yy + 0.5 - scaledRadiusY) * (yy + 0.5 - scaledRadiusY) + / (scaledRadiusY * scaledRadiusY) + - (zz + 0.5 - scaledRadiusZ) * (zz + 0.5 - scaledRadiusZ) + / (scaledRadiusZ * scaledRadiusZ)) + * scaledRadiusX); + if (yy < scaledRadiusY) { kernel[zz][yy] = new double[scaledRadiusX * 2]; - + // Pre-generate kernel for (int xx = 0; xx < scaledRadiusX * 2; xx++) { double dx = (xx + 0.5 - scaledRadiusX) * xFrequency; @@ -789,108 +890,112 @@ public class OpenSimplex2S { kernel[zz][yy][xx] = 0.0; } } - - } else kernel[zz][yy] = kernel[zz][2 * scaledRadiusY - yy - 1]; + + } else + kernel[zz][yy] = kernel[zz][2 * scaledRadiusY - yy - 1]; } } } } } - + public enum LatticeOrientation2D { - // Simplex skew transforms have always been shorthand for the matrices they represent. - // But when we bake the rotation into the skew transform, we need to use the general form. - Standard(GRADIENTS_2D, - 1.366025403784439, 0.366025403784439, 0.366025403784439, 1.366025403784439, - 0.788675134594813, -0.211324865405187, -0.211324865405187, 0.788675134594813), - XBeforeY(GRADIENTS_2D_X_BEFORE_Y, - 0.7071067811865476, 1.224744871380249, -0.7071067811865476, 1.224744871380249, - 0.7071067811865476, -0.7071067811865476, 0.40824829046764305, 0.40824829046764305); - + // Simplex skew transforms have always been shorthand for the matrices + // they represent. + // But when we bake the rotation into the skew transform, we need to use + // the general form. + Standard(GRADIENTS_2D, 1.366025403784439, 0.366025403784439, 0.366025403784439, 1.366025403784439, + 0.788675134594813, -0.211324865405187, -0.211324865405187, + 0.788675134594813), XBeforeY(GRADIENTS_2D_X_BEFORE_Y, 0.7071067811865476, 1.224744871380249, + -0.7071067811865476, 1.224744871380249, 0.7071067811865476, -0.7071067811865476, + 0.40824829046764305, 0.40824829046764305); + Grad2[] gradients; double s00, s01, s10, s11; double t00, t01, t10, t11; - - private LatticeOrientation2D(Grad2[] gradients, - double s00, double s01, double s10, double s11, - double t00, double t01, double t10, double t11) { + + private LatticeOrientation2D(Grad2[] gradients, double s00, double s01, double s10, double s11, double t00, + double t01, double t10, double t11) { this.gradients = gradients; - this.s00 = s00; this.s01 = s01; this.s10 = s10; this.s11 = s11; - this.t00 = t00; this.t01 = t01; this.t10 = t10; this.t11 = t11; + this.s00 = s00; + this.s01 = s01; + this.s10 = s10; + this.s11 = s11; + this.t00 = t00; + this.t01 = t01; + this.t10 = t10; + this.t11 = t11; } } - + public enum LatticeOrientation3D { - // Quaternions for 3D. Could use matrices, but I already wrote this code before I moved them into here. - Classic(GRADIENTS_3D_CLASSIC, 0.577350269189626, 0.577350269189626, 0.577350269189626, 0), - XYBeforeZ(GRADIENTS_3D_XY_BEFORE_Z, 0.3250575836718682, -0.3250575836718682, 0, 0.8880738339771154), - XZBeforeY(GRADIENTS_3D_XZ_BEFORE_Y, -0.3250575836718682, 0, 0.3250575836718682, 0.8880738339771154); - + // Quaternions for 3D. Could use matrices, but I already wrote this code + // before I moved them into here. + Classic(GRADIENTS_3D_CLASSIC, 0.577350269189626, 0.577350269189626, 0.577350269189626, 0), XYBeforeZ( + GRADIENTS_3D_XY_BEFORE_Z, 0.3250575836718682, -0.3250575836718682, 0, 0.8880738339771154), XZBeforeY( + GRADIENTS_3D_XZ_BEFORE_Y, -0.3250575836718682, 0, 0.3250575836718682, 0.8880738339771154); + Grad3[] gradients; double qx, qy, qz, qw; - + private LatticeOrientation3D(Grad3[] gradients, double qx, double qy, double qz, double qw) { this.gradients = gradients; - this.qx = qx; this.qy = qy; this.qz = qz; this.qw = qw; + this.qx = qx; + this.qy = qy; + this.qz = qz; + this.qw = qw; } } - + /* * Gradients */ - + public static class Grad2 { double dx, dy; + public Grad2(double dx, double dy) { - this.dx = dx; this.dy = dy; + this.dx = dx; + this.dy = dy; } } - + public static class Grad3 { double dx, dy, dz; + public Grad3(double dx, double dy, double dz) { - this.dx = dx; this.dy = dy; this.dz = dz; + this.dx = dx; + this.dy = dy; + this.dz = dz; } } - + public static final double N2 = 0.05481866495625118; public static final double N3 = 0.2781926117527186; private static final Grad2[] GRADIENTS_2D, GRADIENTS_2D_X_BEFORE_Y; private static final Grad3[] GRADIENTS_3D, GRADIENTS_3D_CLASSIC, GRADIENTS_3D_XY_BEFORE_Z, GRADIENTS_3D_XZ_BEFORE_Y; static { - + GRADIENTS_2D = new Grad2[PSIZE]; GRADIENTS_2D_X_BEFORE_Y = new Grad2[PSIZE]; - Grad2[] grad2 = { - new Grad2( 0.130526192220052, 0.99144486137381), - new Grad2( 0.38268343236509, 0.923879532511287), - new Grad2( 0.608761429008721, 0.793353340291235), - new Grad2( 0.793353340291235, 0.608761429008721), - new Grad2( 0.923879532511287, 0.38268343236509), - new Grad2( 0.99144486137381, 0.130526192220051), - new Grad2( 0.99144486137381, -0.130526192220051), - new Grad2( 0.923879532511287, -0.38268343236509), - new Grad2( 0.793353340291235, -0.60876142900872), - new Grad2( 0.608761429008721, -0.793353340291235), - new Grad2( 0.38268343236509, -0.923879532511287), - new Grad2( 0.130526192220052, -0.99144486137381), - new Grad2(-0.130526192220052, -0.99144486137381), - new Grad2(-0.38268343236509, -0.923879532511287), - new Grad2(-0.608761429008721, -0.793353340291235), - new Grad2(-0.793353340291235, -0.608761429008721), - new Grad2(-0.923879532511287, -0.38268343236509), - new Grad2(-0.99144486137381, -0.130526192220052), - new Grad2(-0.99144486137381, 0.130526192220051), - new Grad2(-0.923879532511287, 0.38268343236509), - new Grad2(-0.793353340291235, 0.608761429008721), - new Grad2(-0.608761429008721, 0.793353340291235), - new Grad2(-0.38268343236509, 0.923879532511287), - new Grad2(-0.130526192220052, 0.99144486137381) - }; + Grad2[] grad2 = { new Grad2(0.130526192220052, 0.99144486137381), + new Grad2(0.38268343236509, 0.923879532511287), new Grad2(0.608761429008721, 0.793353340291235), + new Grad2(0.793353340291235, 0.608761429008721), new Grad2(0.923879532511287, 0.38268343236509), + new Grad2(0.99144486137381, 0.130526192220051), new Grad2(0.99144486137381, -0.130526192220051), + new Grad2(0.923879532511287, -0.38268343236509), new Grad2(0.793353340291235, -0.60876142900872), + new Grad2(0.608761429008721, -0.793353340291235), new Grad2(0.38268343236509, -0.923879532511287), + new Grad2(0.130526192220052, -0.99144486137381), new Grad2(-0.130526192220052, -0.99144486137381), + new Grad2(-0.38268343236509, -0.923879532511287), new Grad2(-0.608761429008721, -0.793353340291235), + new Grad2(-0.793353340291235, -0.608761429008721), new Grad2(-0.923879532511287, -0.38268343236509), + new Grad2(-0.99144486137381, -0.130526192220052), new Grad2(-0.99144486137381, 0.130526192220051), + new Grad2(-0.923879532511287, 0.38268343236509), new Grad2(-0.793353340291235, 0.608761429008721), + new Grad2(-0.608761429008721, 0.793353340291235), new Grad2(-0.38268343236509, 0.923879532511287), + new Grad2(-0.130526192220052, 0.99144486137381) }; Grad2[] grad2XBeforeY = new Grad2[grad2.length]; for (int i = 0; i < grad2.length; i++) { - grad2[i].dx /= N2; grad2[i].dy /= N2; - + grad2[i].dx /= N2; + grad2[i].dy /= N2; + // Unrotated gradients for XBeforeY 2D double xx = grad2[i].dx * 0.7071067811865476; double yy = grad2[i].dy * 0.7071067811865476; @@ -900,82 +1005,64 @@ public class OpenSimplex2S { GRADIENTS_2D[i] = grad2[i % grad2.length]; GRADIENTS_2D_X_BEFORE_Y[i] = grad2XBeforeY[i % grad2XBeforeY.length]; } - + GRADIENTS_3D = new Grad3[PSIZE]; GRADIENTS_3D_CLASSIC = new Grad3[PSIZE]; GRADIENTS_3D_XY_BEFORE_Z = new Grad3[PSIZE]; GRADIENTS_3D_XZ_BEFORE_Y = new Grad3[PSIZE]; - Grad3[] grad3 = { - new Grad3(-2.22474487139, -2.22474487139, -1.0), - new Grad3(-2.22474487139, -2.22474487139, 1.0), - new Grad3(-3.0862664687972017, -1.1721513422464978, 0.0), - new Grad3(-1.1721513422464978, -3.0862664687972017, 0.0), - new Grad3(-2.22474487139, -1.0, -2.22474487139), - new Grad3(-2.22474487139, 1.0, -2.22474487139), - new Grad3(-1.1721513422464978, 0.0, -3.0862664687972017), - new Grad3(-3.0862664687972017, 0.0, -1.1721513422464978), - new Grad3(-2.22474487139, -1.0, 2.22474487139), - new Grad3(-2.22474487139, 1.0, 2.22474487139), - new Grad3(-3.0862664687972017, 0.0, 1.1721513422464978), - new Grad3(-1.1721513422464978, 0.0, 3.0862664687972017), - new Grad3(-2.22474487139, 2.22474487139, -1.0), - new Grad3(-2.22474487139, 2.22474487139, 1.0), - new Grad3(-1.1721513422464978, 3.0862664687972017, 0.0), - new Grad3(-3.0862664687972017, 1.1721513422464978, 0.0), - new Grad3(-1.0, -2.22474487139, -2.22474487139), - new Grad3( 1.0, -2.22474487139, -2.22474487139), - new Grad3( 0.0, -3.0862664687972017, -1.1721513422464978), - new Grad3( 0.0, -1.1721513422464978, -3.0862664687972017), - new Grad3(-1.0, -2.22474487139, 2.22474487139), - new Grad3( 1.0, -2.22474487139, 2.22474487139), - new Grad3( 0.0, -1.1721513422464978, 3.0862664687972017), - new Grad3( 0.0, -3.0862664687972017, 1.1721513422464978), - new Grad3(-1.0, 2.22474487139, -2.22474487139), - new Grad3( 1.0, 2.22474487139, -2.22474487139), - new Grad3( 0.0, 1.1721513422464978, -3.0862664687972017), - new Grad3( 0.0, 3.0862664687972017, -1.1721513422464978), - new Grad3(-1.0, 2.22474487139, 2.22474487139), - new Grad3( 1.0, 2.22474487139, 2.22474487139), - new Grad3( 0.0, 3.0862664687972017, 1.1721513422464978), - new Grad3( 0.0, 1.1721513422464978, 3.0862664687972017), - new Grad3( 2.22474487139, -2.22474487139, -1.0), - new Grad3( 2.22474487139, -2.22474487139, 1.0), - new Grad3( 1.1721513422464978, -3.0862664687972017, 0.0), - new Grad3( 3.0862664687972017, -1.1721513422464978, 0.0), - new Grad3( 2.22474487139, -1.0, -2.22474487139), - new Grad3( 2.22474487139, 1.0, -2.22474487139), - new Grad3( 3.0862664687972017, 0.0, -1.1721513422464978), - new Grad3( 1.1721513422464978, 0.0, -3.0862664687972017), - new Grad3( 2.22474487139, -1.0, 2.22474487139), - new Grad3( 2.22474487139, 1.0, 2.22474487139), - new Grad3( 1.1721513422464978, 0.0, 3.0862664687972017), - new Grad3( 3.0862664687972017, 0.0, 1.1721513422464978), - new Grad3( 2.22474487139, 2.22474487139, -1.0), - new Grad3( 2.22474487139, 2.22474487139, 1.0), - new Grad3( 3.0862664687972017, 1.1721513422464978, 0.0), - new Grad3( 1.1721513422464978, 3.0862664687972017, 0.0) - }; + Grad3[] grad3 = { new Grad3(-2.22474487139, -2.22474487139, -1.0), + new Grad3(-2.22474487139, -2.22474487139, 1.0), + new Grad3(-3.0862664687972017, -1.1721513422464978, 0.0), + new Grad3(-1.1721513422464978, -3.0862664687972017, 0.0), + new Grad3(-2.22474487139, -1.0, -2.22474487139), new Grad3(-2.22474487139, 1.0, -2.22474487139), + new Grad3(-1.1721513422464978, 0.0, -3.0862664687972017), + new Grad3(-3.0862664687972017, 0.0, -1.1721513422464978), + new Grad3(-2.22474487139, -1.0, 2.22474487139), new Grad3(-2.22474487139, 1.0, 2.22474487139), + new Grad3(-3.0862664687972017, 0.0, 1.1721513422464978), + new Grad3(-1.1721513422464978, 0.0, 3.0862664687972017), new Grad3(-2.22474487139, 2.22474487139, -1.0), + new Grad3(-2.22474487139, 2.22474487139, 1.0), new Grad3(-1.1721513422464978, 3.0862664687972017, 0.0), + new Grad3(-3.0862664687972017, 1.1721513422464978, 0.0), + new Grad3(-1.0, -2.22474487139, -2.22474487139), new Grad3(1.0, -2.22474487139, -2.22474487139), + new Grad3(0.0, -3.0862664687972017, -1.1721513422464978), + new Grad3(0.0, -1.1721513422464978, -3.0862664687972017), + new Grad3(-1.0, -2.22474487139, 2.22474487139), new Grad3(1.0, -2.22474487139, 2.22474487139), + new Grad3(0.0, -1.1721513422464978, 3.0862664687972017), + new Grad3(0.0, -3.0862664687972017, 1.1721513422464978), new Grad3(-1.0, 2.22474487139, -2.22474487139), + new Grad3(1.0, 2.22474487139, -2.22474487139), new Grad3(0.0, 1.1721513422464978, -3.0862664687972017), + new Grad3(0.0, 3.0862664687972017, -1.1721513422464978), new Grad3(-1.0, 2.22474487139, 2.22474487139), + new Grad3(1.0, 2.22474487139, 2.22474487139), new Grad3(0.0, 3.0862664687972017, 1.1721513422464978), + new Grad3(0.0, 1.1721513422464978, 3.0862664687972017), new Grad3(2.22474487139, -2.22474487139, -1.0), + new Grad3(2.22474487139, -2.22474487139, 1.0), new Grad3(1.1721513422464978, -3.0862664687972017, 0.0), + new Grad3(3.0862664687972017, -1.1721513422464978, 0.0), new Grad3(2.22474487139, -1.0, -2.22474487139), + new Grad3(2.22474487139, 1.0, -2.22474487139), new Grad3(3.0862664687972017, 0.0, -1.1721513422464978), + new Grad3(1.1721513422464978, 0.0, -3.0862664687972017), new Grad3(2.22474487139, -1.0, 2.22474487139), + new Grad3(2.22474487139, 1.0, 2.22474487139), new Grad3(1.1721513422464978, 0.0, 3.0862664687972017), + new Grad3(3.0862664687972017, 0.0, 1.1721513422464978), new Grad3(2.22474487139, 2.22474487139, -1.0), + new Grad3(2.22474487139, 2.22474487139, 1.0), new Grad3(3.0862664687972017, 1.1721513422464978, 0.0), + new Grad3(1.1721513422464978, 3.0862664687972017, 0.0) }; Grad3[] grad3Classic = new Grad3[grad3.length]; Grad3[] grad3XYBeforeZ = new Grad3[grad3.length]; Grad3[] grad3XZBeforeY = new Grad3[grad3.length]; for (int i = 0; i < grad3.length; i++) { - grad3[i].dx /= N3; grad3[i].dy /= N3; grad3[i].dz /= N3; - double gxr = grad3[i].dx, gyr = grad3[i].dy, gzr = grad3[i].dz; + grad3[i].dx /= N3; + grad3[i].dy /= N3; + grad3[i].dz /= N3; + double gxr = grad3[i].dx, gyr = grad3[i].dy, gzr = grad3[i].dz; // Unrotated gradients for classic 3D double grr = (2.0 / 3.0) * (gxr + gyr + gzr); -// double dx = grr - gxr, dy = grr - gyr, dz = grr - gzr; - grad3Classic[i] = new Grad3( grr - gxr, grr - gyr, grr - gzr ); - + // double dx = grr - gxr, dy = grr - gyr, dz = grr - gzr; + grad3Classic[i] = new Grad3(grr - gxr, grr - gyr, grr - gzr); + // Unrotated gradients for XYBeforeZ 3D double s2 = (gxr + gyr) * -0.211324865405187; double zz = gzr * 0.577350269189626; - grad3XYBeforeZ[i] = new Grad3( gxr + s2 + zz, gyr + s2 + zz, (gzr - gxr - gyr) * 0.577350269189626 ); - + grad3XYBeforeZ[i] = new Grad3(gxr + s2 + zz, gyr + s2 + zz, (gzr - gxr - gyr) * 0.577350269189626); + // Unrotated gradients for plane-first 3D s2 = (gxr + gzr) * -0.211324865405187; double yy = gyr * 0.577350269189626; - grad3XZBeforeY[i] = new Grad3( gxr + s2 + yy, (gyr - gxr - gzr) * 0.577350269189626, gzr + s2 + yy ); + grad3XZBeforeY[i] = new Grad3(gxr + s2 + yy, (gyr - gxr - gzr) * 0.577350269189626, gzr + s2 + yy); } for (int i = 0; i < PSIZE; i++) { GRADIENTS_3D[i] = grad3[i % grad3.length]; diff --git a/src/main/java/ru/windcorp/jputil/ArrayUtil.java b/src/main/java/ru/windcorp/jputil/ArrayUtil.java index 4c57314..7ae5dcc 100644 --- a/src/main/java/ru/windcorp/jputil/ArrayUtil.java +++ b/src/main/java/ru/windcorp/jputil/ArrayUtil.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil; import java.lang.reflect.Array; @@ -611,8 +611,7 @@ public class ArrayUtil { int end = offset + length; if (end > arrayLength || offset < 0) throw new IllegalArgumentException( - "Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")" - ); + "Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")"); return length; } @@ -628,8 +627,7 @@ public class ArrayUtil { if (end > arrayLength || start < 0) throw new IllegalArgumentException( - "Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")" - ); + "Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")"); return end; } diff --git a/src/main/java/ru/windcorp/jputil/CSVWriter.java b/src/main/java/ru/windcorp/jputil/CSVWriter.java index 57ddec0..b74d88c 100644 --- a/src/main/java/ru/windcorp/jputil/CSVWriter.java +++ b/src/main/java/ru/windcorp/jputil/CSVWriter.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil; import java.io.OutputStream; diff --git a/src/main/java/ru/windcorp/jputil/PrimitiveUtil.java b/src/main/java/ru/windcorp/jputil/PrimitiveUtil.java index 7579413..28c6435 100644 --- a/src/main/java/ru/windcorp/jputil/PrimitiveUtil.java +++ b/src/main/java/ru/windcorp/jputil/PrimitiveUtil.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil; import java.util.HashMap; @@ -30,18 +30,8 @@ public class PrimitiveUtil { private static final Map, Object> PRIMITIVE_TO_NULL = new HashMap<>(); static { - for ( - Class boxed : new Class[] { - Boolean.class, - Byte.class, - Short.class, - Character.class, - Integer.class, - Long.class, - Float.class, - Double.class - } - ) { + for (Class boxed : new Class[] { Boolean.class, Byte.class, Short.class, Character.class, Integer.class, + Long.class, Float.class, Double.class }) { try { PRIMITIVE_TO_BOXED.put((Class) boxed.getField("TYPE").get(null), boxed); } catch (Exception e) { diff --git a/src/main/java/ru/windcorp/jputil/SyncStreams.java b/src/main/java/ru/windcorp/jputil/SyncStreams.java index 9b2bc3a..80ed01b 100644 --- a/src/main/java/ru/windcorp/jputil/SyncStreams.java +++ b/src/main/java/ru/windcorp/jputil/SyncStreams.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil; import java.util.function.*; @@ -40,8 +40,7 @@ import java.util.stream.Stream; /** * Contains static methods to create {@link Stream Streams} that synchronize - * their - * * terminal operations on a given monitor. * @@ -50,7 +49,7 @@ import java.util.stream.Stream; */ // SonarLint: "Stream.peek" should be used with caution (java:S3864) -// We are implementing Stream, so peek() is required. +// We are implementing Stream, so peek() is required. @SuppressWarnings("squid:S3864") public class SyncStreams { @@ -1070,21 +1069,18 @@ public class SyncStreams { } /** - * Wraps the given {@link Stream} to make all - * * terminal operations acquire the provided monitor's lock before - * execution. Intermediate operations - * return streams that are also synchronized on the same object. The created - * stream will behave identically - * to the provided stream in all other aspects. Use this to synchronize - * access to stream's source. + * execution. Intermediate operations return streams that are also + * synchronized on the same object. The created stream will behave + * identically to the provided stream in all other aspects. Use this to + * synchronize access to stream's source. *

* The returned {@code Stream}'s {@link Stream#iterator() iterator()} and - * {@link Stream#spliterator() - * spliterator()} methods return regular non-synchronized iterators and - * spliterators respectively. It - * is the user's responsibility to avoid concurrency issues: + * {@link Stream#spliterator() spliterator()} methods return regular + * non-synchronized iterators and spliterators respectively. It is the + * user's responsibility to avoid concurrency issues: * *

 	 * synchronized (stream.getMonitor()) {
@@ -1103,14 +1099,17 @@ public class SyncStreams {
 	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
 	 * 
* - * @param the class of objects in the Stream - * @param stream the stream to wrap. - * @param monitor the object that the stream will use for synchronization. - * When {@code null}, the stream - * will synchronize on itself. + * @param + * the class of objects in the Stream + * @param stream + * the stream to wrap. + * @param monitor + * the object that the stream will use for synchronization. When + * {@code null}, the stream will synchronize on itself. * @return a {@link SyncStream SyncStream<T>} synchronized on * {@code monitor} and backed by {@code stream}. - * @throws NullPointerException if {@code stream == null}. + * @throws NullPointerException + * if {@code stream == null}. */ public static SyncStream synchronizedStream(Stream stream, Object monitor) { Objects.requireNonNull(stream, "stream cannot be null"); @@ -1118,22 +1117,19 @@ public class SyncStreams { } /** - * Wraps the given {@link IntStream} to make all - * * terminal operations acquire the provided monitor's lock before - * execution. Intermediate operations - * return streams that are also synchronized on the same object. The created - * stream will behave identically - * to the provided stream in all other aspects. Use this to synchronize - * access to stream's source. + * execution. Intermediate operations return streams that are also + * synchronized on the same object. The created stream will behave + * identically to the provided stream in all other aspects. Use this to + * synchronize access to stream's source. *

* The returned {@code IntStream}'s {@link IntStream#iterator() - * iterator()} and - * {@link IntStream#spliterator() spliterator()} methods return regular - * non-synchronized iterators and - * spliterators respectively. It is the user's responsibility to avoid - * concurrency issues: + * iterator()} and {@link IntStream#spliterator() spliterator()} methods + * return regular non-synchronized iterators and spliterators + * respectively. It is the user's responsibility to avoid concurrency + * issues: * *

 	 * synchronized (stream.getMonitor()) {
@@ -1152,13 +1148,15 @@ public class SyncStreams {
 	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
 	 * 
* - * @param stream the stream to wrap. - * @param monitor the object that the stream will use for synchronization. - * When {@code null}, the stream - * will synchronize on itself. + * @param stream + * the stream to wrap. + * @param monitor + * the object that the stream will use for synchronization. When + * {@code null}, the stream will synchronize on itself. * @return a {@link SyncIntStream} synchronized on {@code monitor} and * backed by {@code stream}. - * @throws NullPointerException if {@code stream == null}. + * @throws NullPointerException + * if {@code stream == null}. */ public static SyncIntStream synchronizedStream(IntStream stream, Object monitor) { Objects.requireNonNull(stream, "stream cannot be null"); @@ -1166,22 +1164,19 @@ public class SyncStreams { } /** - * Wraps the given {@link LongStream} to make all - * * terminal operations acquire the provided monitor's lock before - * execution. Intermediate operations - * return streams that are also synchronized on the same object. The created - * stream will behave identically - * to the provided stream in all other aspects. Use this to synchronize - * access to stream's source. + * execution. Intermediate operations return streams that are also + * synchronized on the same object. The created stream will behave + * identically to the provided stream in all other aspects. Use this to + * synchronize access to stream's source. *

* The returned {@code LongStream}'s {@link LongStream#iterator() - * iterator()} and - * {@link LongStream#spliterator() spliterator()} methods return regular - * non-synchronized iterators and - * spliterators respectively. It is the user's responsibility to avoid - * concurrency issues: + * iterator()} and {@link LongStream#spliterator() spliterator()} methods + * return regular non-synchronized iterators and spliterators + * respectively. It is the user's responsibility to avoid concurrency + * issues: * *

 	 * synchronized (stream.getMonitor()) {
@@ -1200,13 +1195,15 @@ public class SyncStreams {
 	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
 	 * 
* - * @param stream the stream to wrap. - * @param monitor the object that the stream will use for synchronization. - * When {@code null}, the stream - * will synchronize on itself. + * @param stream + * the stream to wrap. + * @param monitor + * the object that the stream will use for synchronization. When + * {@code null}, the stream will synchronize on itself. * @return a {@link SyncLongStream} synchronized on {@code monitor} and * backed by {@code stream}. - * @throws NullPointerException if {@code stream == null}. + * @throws NullPointerException + * if {@code stream == null}. */ public static SyncLongStream synchronizedStream(LongStream stream, Object monitor) { Objects.requireNonNull(stream, "stream cannot be null"); @@ -1214,22 +1211,19 @@ public class SyncStreams { } /** - * Wraps the given {@link DoubleStream} to make all - * * terminal operations acquire the provided monitor's lock before - * execution. Intermediate operations - * return streams that are also synchronized on the same object. The created - * stream will behave identically - * to the provided stream in all other aspects. Use this to synchronize - * access to stream's source. + * execution. Intermediate operations return streams that are also + * synchronized on the same object. The created stream will behave + * identically to the provided stream in all other aspects. Use this to + * synchronize access to stream's source. *

* The returned {@code DoubleStream}'s {@link DoubleStream#iterator() - * iterator()} and - * {@link DoubleStream#spliterator() spliterator()} methods return regular - * non-synchronized iterators and - * spliterators respectively. It is the user's responsibility to avoid - * concurrency issues: + * iterator()} and {@link DoubleStream#spliterator() spliterator()} methods + * return regular non-synchronized iterators and spliterators + * respectively. It is the user's responsibility to avoid concurrency + * issues: * *

 	 * synchronized (stream.getMonitor()) {
@@ -1248,13 +1242,15 @@ public class SyncStreams {
 	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
 	 * 
* - * @param stream the stream to wrap. - * @param monitor the object that the stream will use for synchronization. - * When {@code null}, the stream - * will synchronize on itself. + * @param stream + * the stream to wrap. + * @param monitor + * the object that the stream will use for synchronization. When + * {@code null}, the stream will synchronize on itself. * @return a {@link SyncDoubleStream} synchronized on {@code monitor} and * backed by {@code stream}. - * @throws NullPointerException if {@code stream == null}. + * @throws NullPointerException + * if {@code stream == null}. */ public static SyncDoubleStream synchronizedStream(DoubleStream stream, Object monitor) { Objects.requireNonNull(stream, "stream cannot be null"); diff --git a/src/main/java/ru/windcorp/jputil/SyntaxException.java b/src/main/java/ru/windcorp/jputil/SyntaxException.java index 02cc3c4..8fdb710 100644 --- a/src/main/java/ru/windcorp/jputil/SyntaxException.java +++ b/src/main/java/ru/windcorp/jputil/SyntaxException.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil; public class SyntaxException extends Exception { diff --git a/src/main/java/ru/windcorp/jputil/chars/CharArrayIterator.java b/src/main/java/ru/windcorp/jputil/chars/CharArrayIterator.java index be0940d..659b567 100644 --- a/src/main/java/ru/windcorp/jputil/chars/CharArrayIterator.java +++ b/src/main/java/ru/windcorp/jputil/chars/CharArrayIterator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; import java.text.CharacterIterator; @@ -108,7 +108,7 @@ public class CharArrayIterator implements CharacterIterator { return pos; } -// @SuppressWarnings("all") Just STFU, this _is_ terrific + // @SuppressWarnings("all") Just STFU, this _is_ terrific // SonarLint: "clone" should not be overridden (java:S2975) // And I wouldn't have done that if only CharacterIterator had not required diff --git a/src/main/java/ru/windcorp/jputil/chars/CharConsumer.java b/src/main/java/ru/windcorp/jputil/chars/CharConsumer.java index 7b68bb1..55448b0 100644 --- a/src/main/java/ru/windcorp/jputil/chars/CharConsumer.java +++ b/src/main/java/ru/windcorp/jputil/chars/CharConsumer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; import java.util.function.IntConsumer; diff --git a/src/main/java/ru/windcorp/jputil/chars/CharConsumers.java b/src/main/java/ru/windcorp/jputil/chars/CharConsumers.java index 1ac7973..12a518d 100644 --- a/src/main/java/ru/windcorp/jputil/chars/CharConsumers.java +++ b/src/main/java/ru/windcorp/jputil/chars/CharConsumers.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; import java.util.Objects; diff --git a/src/main/java/ru/windcorp/jputil/chars/CharPredicate.java b/src/main/java/ru/windcorp/jputil/chars/CharPredicate.java index 03ded02..c02beed 100644 --- a/src/main/java/ru/windcorp/jputil/chars/CharPredicate.java +++ b/src/main/java/ru/windcorp/jputil/chars/CharPredicate.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; import java.util.Arrays; diff --git a/src/main/java/ru/windcorp/jputil/chars/CharSupplier.java b/src/main/java/ru/windcorp/jputil/chars/CharSupplier.java index 0743d79..2a9749b 100644 --- a/src/main/java/ru/windcorp/jputil/chars/CharSupplier.java +++ b/src/main/java/ru/windcorp/jputil/chars/CharSupplier.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; import java.util.function.IntSupplier; diff --git a/src/main/java/ru/windcorp/jputil/chars/EscapeException.java b/src/main/java/ru/windcorp/jputil/chars/EscapeException.java index 935f72f..544c50f 100644 --- a/src/main/java/ru/windcorp/jputil/chars/EscapeException.java +++ b/src/main/java/ru/windcorp/jputil/chars/EscapeException.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; public class EscapeException extends Exception { diff --git a/src/main/java/ru/windcorp/jputil/chars/Escaper.java b/src/main/java/ru/windcorp/jputil/chars/Escaper.java index f19f6c7..a07dc08 100644 --- a/src/main/java/ru/windcorp/jputil/chars/Escaper.java +++ b/src/main/java/ru/windcorp/jputil/chars/Escaper.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; import java.text.CharacterIterator; @@ -103,14 +103,8 @@ public class Escaper { } - public static final Escaper JAVA = new Escaper( - '\\', - 'u', - "tbnrf'\"".toCharArray(), - "\t\b\n\r\f\'\"".toCharArray(), - true, - true - ); + public static final Escaper JAVA = new Escaper('\\', 'u', "tbnrf'\"".toCharArray(), "\t\b\n\r\f\'\"".toCharArray(), + true, true); private final char escapeChar; private final char unicodeEscapeChar; @@ -120,14 +114,8 @@ public class Escaper { private final boolean preferUnicode; private final boolean strict; - protected Escaper( - char escapeChar, - char unicodeEscapeChar, - char[] safes, - char[] unsafes, - boolean preferUnicode, - boolean strict - ) { + protected Escaper(char escapeChar, char unicodeEscapeChar, char[] safes, char[] unsafes, boolean preferUnicode, + boolean strict) { this.escapeChar = escapeChar; this.unicodeEscapeChar = unicodeEscapeChar; this.safes = safes; @@ -152,8 +140,7 @@ public class Escaper { for (char c : unsafes) { if (c == escapeChar) throw new IllegalArgumentException( - "Unsafe characters contain escape chatacter (escape character is escaped automatically)" - ); + "Unsafe characters contain escape chatacter (escape character is escaped automatically)"); if (c == unicodeEscapeChar) throw new IllegalArgumentException("Unsafe characters contain Unicode escape chatacter"); } @@ -173,11 +160,7 @@ public class Escaper { end = Integer.MAX_VALUE; else end = src.getPosition() + length; - while ( - src.has() && - src.getPosition() < end && - (until == null || !until.test(src.current())) - ) + while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current()))) escape(src.consume(), output); } @@ -225,11 +208,7 @@ public class Escaper { int result = 0; - while ( - src.has() && - src.getPosition() < end && - (until == null || !until.test(src.current())) - ) { + while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current()))) { result += getEscapedLength(src.consume()); } @@ -257,11 +236,7 @@ public class Escaper { end = Integer.MAX_VALUE; else end = src.getPosition() + length; - while ( - src.has() && - src.getPosition() < end && - (until == null || !until.test(src.current())) - ) { + while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current()))) { output.accept(unescapeOneSequence(src)); } } @@ -282,10 +257,8 @@ public class Escaper { if (src.current() == unicodeEscapeChar) { src.next(); - return (char) (hexValue(src.consume()) << (4 * 3) | - hexValue(src.consume()) << (4 * 2) | - hexValue(src.consume()) << (4 * 1) | - hexValue(src.consume()) << (4 * 0)); + return (char) (hexValue(src.consume()) << (4 * 3) | hexValue(src.consume()) << (4 * 2) + | hexValue(src.consume()) << (4 * 1) | hexValue(src.consume()) << (4 * 0)); } int index = ArrayUtil.firstIndexOf(safes, src.current()); @@ -315,11 +288,7 @@ public class Escaper { int result = 0; - while ( - src.has() && - src.getPosition() < end && - (until == null || !until.test(src.current())) - ) { + while (src.has() && src.getPosition() < end && (until == null || !until.test(src.current()))) { skipOneSequence(src); result++; } @@ -328,11 +297,7 @@ public class Escaper { } public void skipOneSequence(CharReader src) { - if ( - src.current() == escapeChar - && - src.next() == unicodeEscapeChar - ) { + if (src.current() == escapeChar && src.next() == unicodeEscapeChar) { src.advance(4); } src.next(); diff --git a/src/main/java/ru/windcorp/jputil/chars/FancyCharacterIterator.java b/src/main/java/ru/windcorp/jputil/chars/FancyCharacterIterator.java index 183b672..da4e81e 100644 --- a/src/main/java/ru/windcorp/jputil/chars/FancyCharacterIterator.java +++ b/src/main/java/ru/windcorp/jputil/chars/FancyCharacterIterator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; import java.text.CharacterIterator; @@ -86,7 +86,7 @@ public class FancyCharacterIterator implements CharacterIterator { return sb.toString(); } -// @SuppressWarnings("all") Just STFU, this _is_ terrific + // @SuppressWarnings("all") Just STFU, this _is_ terrific // SonarLint: "clone" should not be overridden (java:S2975) // And I wouldn't have done that if only CharacterIterator had not required diff --git a/src/main/java/ru/windcorp/jputil/chars/IndentedStringBuilder.java b/src/main/java/ru/windcorp/jputil/chars/IndentedStringBuilder.java index 92ba836..21afc6f 100644 --- a/src/main/java/ru/windcorp/jputil/chars/IndentedStringBuilder.java +++ b/src/main/java/ru/windcorp/jputil/chars/IndentedStringBuilder.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; public class IndentedStringBuilder { diff --git a/src/main/java/ru/windcorp/jputil/chars/StringUtil.java b/src/main/java/ru/windcorp/jputil/chars/StringUtil.java index f08018a..eb66975 100644 --- a/src/main/java/ru/windcorp/jputil/chars/StringUtil.java +++ b/src/main/java/ru/windcorp/jputil/chars/StringUtil.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; import java.io.IOException; @@ -41,13 +41,8 @@ public class StringUtil { private static final String EMPTY_PLACEHOLDER = "[empty]"; private static final String DEFAULT_SEPARATOR = "; "; - public static String arrayToString( - T[] array, - String separator, - String empty, - String nullPlaceholder, - String nullArray - ) { + public static String arrayToString(T[] array, String separator, String empty, String nullPlaceholder, + String nullArray) { if (separator == null) { throw new IllegalArgumentException(new NullPointerException()); @@ -79,13 +74,8 @@ public class StringUtil { return arrayToString(array, DEFAULT_SEPARATOR); } - public static String iteratorToString( - Iterator iterator, - String separator, - String empty, - String nullPlaceholder, - String nullIterator - ) { + public static String iteratorToString(Iterator iterator, String separator, String empty, String nullPlaceholder, + String nullIterator) { if (separator == null) { throw new IllegalArgumentException(new NullPointerException()); @@ -119,13 +109,8 @@ public class StringUtil { return iteratorToString(iterator, DEFAULT_SEPARATOR); } - public static String iterableToString( - Iterable iterable, - String separator, - String empty, - String nullPlaceholder, - String nullIterable - ) { + public static String iterableToString(Iterable iterable, String separator, String empty, String nullPlaceholder, + String nullIterable) { if (separator == null) { throw new IllegalArgumentException(new NullPointerException()); @@ -146,14 +131,8 @@ public class StringUtil { return iterableToString(iterable, DEFAULT_SEPARATOR); } - public static String supplierToString( - IntFunction supplier, - int length, - String separator, - String empty, - String nullPlaceholder, - String nullSupplier - ) { + public static String supplierToString(IntFunction supplier, int length, String separator, String empty, + String nullPlaceholder, String nullSupplier) { if (separator == null) throw new IllegalArgumentException(new NullPointerException()); @@ -163,28 +142,15 @@ public class StringUtil { return empty; if (length > 0) { - return supplierToStringExactly( - supplier, - length, - separator, - nullPlaceholder - ); + return supplierToStringExactly(supplier, length, separator, nullPlaceholder); } else { - return supplierToStringUntilNull( - supplier, - separator, - empty - ); + return supplierToStringUntilNull(supplier, separator, empty); } } - private static String supplierToStringExactly( - IntFunction supplier, - int length, - String separator, - String nullPlaceholder - ) { + private static String supplierToStringExactly(IntFunction supplier, int length, String separator, + String nullPlaceholder) { T element = supplier.apply(0); StringBuilder sb = new StringBuilder(element == null ? nullPlaceholder : element.toString()); @@ -198,11 +164,7 @@ public class StringUtil { return sb.toString(); } - private static String supplierToStringUntilNull( - IntFunction supplier, - String separator, - String empty - ) { + private static String supplierToStringUntilNull(IntFunction supplier, String separator, String empty) { T element = supplier.apply(0); if (element == null) { @@ -366,11 +328,7 @@ public class StringUtil { StringBuilder sb = new StringBuilder(); charLoop: for (char c : src.toCharArray()) { - if ( - (resultIndex + 1) < arrayLength - && - test.test(c) - ) { + if ((resultIndex + 1) < arrayLength && test.test(c)) { result[resultIndex] = resetStringBuilder(sb); ++resultIndex; continue charLoop; @@ -389,17 +347,17 @@ public class StringUtil { * index. *

* Indices {@code 0} and {@code src.length() - 1} produce {@code str} - * excluding - * the specified character and {@code ""}. + * excluding the specified character and {@code ""}. *

* - * @param src the String to split - * @param at index to split at - * @throws IllegalArgumentException if the index is out of bounds for - * {@code src} + * @param src + * the String to split + * @param at + * index to split at + * @throws IllegalArgumentException + * if the index is out of bounds for {@code src} * @return an array containing the substrings, in order of encounter in - * {@code src}. - * Its length is always 2. + * {@code src}. Its length is always 2. */ public static String[] splitAt(String src, int at) { Objects.requireNonNull(src, "src"); @@ -416,10 +374,7 @@ public class StringUtil { return new String[] { src.substring(0, src.length() - 1), "" }; } - return new String[] { - src.substring(0, at), - src.substring(at + 1) - }; + return new String[] { src.substring(0, at), src.substring(at + 1) }; } /** @@ -427,8 +382,7 @@ public class StringUtil { * indices. *

* Indices {@code 0} and {@code src.length() - 1} produce extra zero-length - * outputs. - * Duplicate indices produce extra zero-length outputs. + * outputs. Duplicate indices produce extra zero-length outputs. *

* Examples: * @@ -439,13 +393,14 @@ public class StringUtil { * splitAt("a.b", 1, 1, 1) -> {"a", "", "", "b"} * * - * @param src the String to split - * @param at indices to split at, in any order - * @throws IllegalArgumentException if some index is out of bounds for - * {@code src} + * @param src + * the String to split + * @param at + * indices to split at, in any order + * @throws IllegalArgumentException + * if some index is out of bounds for {@code src} * @return an array containing the substrings, in order of encounter in - * {@code src}. - * Its length is always {@code at.length + 1}. + * {@code src}. Its length is always {@code at.length + 1}. */ public static String[] splitAt(String src, int... at) { Objects.requireNonNull(src, "src"); @@ -553,10 +508,8 @@ public class StringUtil { } if (endPos < beginPos) { - throw new IllegalArgumentException( - "endPos must be greater than or equal to beginPos (endPos=" - + endPos + ", beginPos=" + beginPos + ")" - ); + throw new IllegalArgumentException("endPos must be greater than or equal to beginPos (endPos=" + endPos + + ", beginPos=" + beginPos + ")"); } if (endPos >= Math.min(a.length, b.length)) { @@ -592,8 +545,7 @@ public class StringUtil { /** * Finds and returns the index of the specified appearance of the specified - * character - * in the given array. The search starts at index 0. + * character in the given array. The search starts at index 0. *

* Examples: *

@@ -630,10 +582,12 @@ public class StringUtil { * * * - * @param src - the array to search in. - * @param target - the character to search for. - * @param skip - the amount of target characters to be - * skipped. + * @param src + * - the array to search in. + * @param target + * - the character to search for. + * @param skip + * - the amount of target characters to be skipped. * @return The index of the skip+1th target * character or -1, if none found. * @see StringUtil#indexFromEnd(char[], char, int) @@ -653,8 +607,7 @@ public class StringUtil { /** * Finds and returns the index of the specified appearance of the specified - * character - * in the given array. The search starts at index + * character in the given array. The search starts at index * src.length - 1. *

* Examples: @@ -692,13 +645,15 @@ public class StringUtil { * * * - * @param src - the array to search in. - * @param target - the character to search for. - * @param skip - the amount of target characters to be - * skipped. + * @param src + * - the array to search in. + * @param target + * - the character to search for. + * @param skip + * - the amount of target characters to be skipped. * @return The index of the skip+1th - * targetcharacter - * from the end of the array or -1, if none found. + * targetcharacter from the end of the array or -1, if + * none found. * @see StringUtil#indexFromBeginning(char[], char, int) */ public static int indexFromEnd(char[] src, char target, int skip) { @@ -873,12 +828,8 @@ public class StringUtil { return result; } - private static void buildCombinations( - StringBuilder sb, - Collection result, - Iterable[] parts, - int index - ) { + private static void buildCombinations(StringBuilder sb, Collection result, Iterable[] parts, + int index) { if (index >= parts.length) { result.add(sb.toString()); } else { @@ -904,13 +855,8 @@ public class StringUtil { return result; } - private static void buildCombinations( - StringBuilder sb, - String[] result, - int[] resultIndex, - String[][] parts, - int index - ) { + private static void buildCombinations(StringBuilder sb, String[] result, int[] resultIndex, String[][] parts, + int index) { if (index >= parts.length) { result[resultIndex[0]++] = sb.toString(); } else { @@ -985,10 +931,7 @@ public class StringUtil { } private static char hexDigit(long value, int digit) { - return hexDigit( - (int) (value >>> (4 * digit)) - & 0xF - ); + return hexDigit((int) (value >>> (4 * digit)) & 0xF); } public static char hexDigit(int value) { diff --git a/src/main/java/ru/windcorp/jputil/chars/UncheckedEscapeException.java b/src/main/java/ru/windcorp/jputil/chars/UncheckedEscapeException.java index 33717ee..66b7002 100644 --- a/src/main/java/ru/windcorp/jputil/chars/UncheckedEscapeException.java +++ b/src/main/java/ru/windcorp/jputil/chars/UncheckedEscapeException.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; public class UncheckedEscapeException extends RuntimeException { diff --git a/src/main/java/ru/windcorp/jputil/chars/WordReader.java b/src/main/java/ru/windcorp/jputil/chars/WordReader.java index 22d6969..04dc5b6 100644 --- a/src/main/java/ru/windcorp/jputil/chars/WordReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/WordReader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars; import java.io.IOException; diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/AbstractCharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/AbstractCharReader.java index d31e092..aacf905 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/AbstractCharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/AbstractCharReader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars.reader; /** @@ -27,10 +27,9 @@ public abstract class AbstractCharReader implements CharReader { /** * Current position of this CharReader. The reader maps its input to - * positions starting from 0. - * Positions that are negative or lower than 0 are invalid. - * {@link #current()} - * will throw an exception if position is invalid. + * positions starting from 0. Positions that are negative or lower than 0 + * are invalid. {@link #current()} will throw an exception if position is + * invalid. */ protected int position = 0; diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/ArrayCharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/ArrayCharReader.java index f12f590..09f5e6c 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/ArrayCharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/ArrayCharReader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars.reader; import java.util.Objects; diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/BufferedCharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/BufferedCharReader.java index 83ae6b2..36e6eef 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/BufferedCharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/BufferedCharReader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars.reader; /** @@ -51,9 +51,12 @@ public abstract class BufferedCharReader extends AbstractCharReader { /** * Acquires next characters and stores them in the array. * - * @param buffer the output array - * @param offset index of the first character - * @param length maximum amount of characters to be pulled + * @param buffer + * the output array + * @param offset + * index of the first character + * @param length + * maximum amount of characters to be pulled * @return the amount of characters actually pulled */ protected int pullChars(char[] buffer, int offset, int length) { diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/CharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/CharReader.java index 147daf3..01f21b9 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/CharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/CharReader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars.reader; import java.io.IOException; @@ -30,7 +30,7 @@ import ru.windcorp.jputil.chars.Escaper; */ // SonarLint: Constants should not be defined in interfaces (java:S1214) -// DONE is an essential part of the interface +// DONE is an essential part of the interface @SuppressWarnings("squid:S1214") public interface CharReader { @@ -179,8 +179,7 @@ public interface CharReader { /** * Skips to the end of the current line. Both "\n", - * "\r" - * and "\r\n" are considered line separators. + * "\r" and "\r\n" are considered line separators. * * @return the amount of characters in the skipped line */ diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/CharReaders.java b/src/main/java/ru/windcorp/jputil/chars/reader/CharReaders.java index a181dbf..d6978a0 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/CharReaders.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/CharReaders.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars.reader; import java.io.InputStream; diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/ReaderCharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/ReaderCharReader.java index 51a88db..fec35b2 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/ReaderCharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/ReaderCharReader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars.reader; import java.io.IOException; diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/StringCharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/StringCharReader.java index 5836d15..b8be2f8 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/StringCharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/StringCharReader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.chars.reader; import java.util.Objects; @@ -38,8 +38,7 @@ public class StringCharReader extends AbstractCharReader { int end = offset + length; if (end > str.length() || offset < 0) throw new IllegalArgumentException( - "String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")" - ); + "String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")"); this.offset = offset; this.length = length; diff --git a/src/main/java/ru/windcorp/jputil/functions/FloatSupplier.java b/src/main/java/ru/windcorp/jputil/functions/FloatSupplier.java index a157032..774e36b 100644 --- a/src/main/java/ru/windcorp/jputil/functions/FloatSupplier.java +++ b/src/main/java/ru/windcorp/jputil/functions/FloatSupplier.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.functions; @FunctionalInterface diff --git a/src/main/java/ru/windcorp/jputil/functions/ThrowingBiConsumer.java b/src/main/java/ru/windcorp/jputil/functions/ThrowingBiConsumer.java index be7cb8f..2ed41a3 100644 --- a/src/main/java/ru/windcorp/jputil/functions/ThrowingBiConsumer.java +++ b/src/main/java/ru/windcorp/jputil/functions/ThrowingBiConsumer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.functions; import java.util.function.BiConsumer; @@ -44,9 +44,16 @@ public interface ThrowingBiConsumer { } public static ThrowingBiConsumer concat( - ThrowingBiConsumer first, - ThrowingBiConsumer second - ) { + ThrowingBiConsumer first, + ThrowingBiConsumer second) { + return (t, u) -> { + first.accept(t, u); + second.accept(t, u); + }; + } + + public static ThrowingBiConsumer concat(BiConsumer first, + ThrowingBiConsumer second) { return (t, u) -> { first.accept(t, u); second.accept(t, u); @@ -54,19 +61,7 @@ public interface ThrowingBiConsumer { } public static ThrowingBiConsumer concat( - BiConsumer first, - ThrowingBiConsumer second - ) { - return (t, u) -> { - first.accept(t, u); - second.accept(t, u); - }; - } - - public static ThrowingBiConsumer concat( - ThrowingBiConsumer first, - BiConsumer second - ) { + ThrowingBiConsumer first, BiConsumer second) { return (t, u) -> { first.accept(t, u); second.accept(t, u); diff --git a/src/main/java/ru/windcorp/jputil/functions/ThrowingConsumer.java b/src/main/java/ru/windcorp/jputil/functions/ThrowingConsumer.java index 14449ca..e89bde5 100644 --- a/src/main/java/ru/windcorp/jputil/functions/ThrowingConsumer.java +++ b/src/main/java/ru/windcorp/jputil/functions/ThrowingConsumer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.functions; import java.util.function.BiConsumer; @@ -39,30 +39,24 @@ public interface ThrowingConsumer { }; } - public static ThrowingConsumer concat( - ThrowingConsumer first, - ThrowingConsumer second - ) { + public static ThrowingConsumer concat(ThrowingConsumer first, + ThrowingConsumer second) { return t -> { first.accept(t); second.accept(t); }; } - public static ThrowingConsumer concat( - Consumer first, - ThrowingConsumer second - ) { + public static ThrowingConsumer concat(Consumer first, + ThrowingConsumer second) { return t -> { first.accept(t); second.accept(t); }; } - public static ThrowingConsumer concat( - ThrowingConsumer first, - Consumer second - ) { + public static ThrowingConsumer concat(ThrowingConsumer first, + Consumer second) { return t -> { first.accept(t); second.accept(t); diff --git a/src/main/java/ru/windcorp/jputil/functions/ThrowingFunction.java b/src/main/java/ru/windcorp/jputil/functions/ThrowingFunction.java index afdd078..7c32b16 100644 --- a/src/main/java/ru/windcorp/jputil/functions/ThrowingFunction.java +++ b/src/main/java/ru/windcorp/jputil/functions/ThrowingFunction.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.functions; import java.util.function.BiConsumer; @@ -28,10 +28,8 @@ public interface ThrowingFunction { R apply(T t) throws E; @SuppressWarnings("unchecked") - default Function withHandler( - BiConsumer handler, - Function value - ) { + default Function withHandler(BiConsumer handler, + Function value) { return t -> { try { return apply(t); @@ -58,23 +56,18 @@ public interface ThrowingFunction { } public static ThrowingFunction compose( - ThrowingFunction first, - ThrowingFunction second - ) { + ThrowingFunction first, + ThrowingFunction second) { + return t -> second.apply(first.apply(t)); + } + + public static ThrowingFunction compose(Function first, + ThrowingFunction second) { return t -> second.apply(first.apply(t)); } public static ThrowingFunction compose( - Function first, - ThrowingFunction second - ) { - return t -> second.apply(first.apply(t)); - } - - public static ThrowingFunction compose( - ThrowingFunction first, - Function second - ) { + ThrowingFunction first, Function second) { return t -> second.apply(first.apply(t)); } diff --git a/src/main/java/ru/windcorp/jputil/functions/ThrowingRunnable.java b/src/main/java/ru/windcorp/jputil/functions/ThrowingRunnable.java index f27429b..f93ea61 100644 --- a/src/main/java/ru/windcorp/jputil/functions/ThrowingRunnable.java +++ b/src/main/java/ru/windcorp/jputil/functions/ThrowingRunnable.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.functions; import java.util.function.Consumer; @@ -38,10 +38,8 @@ public interface ThrowingRunnable { }; } - public static ThrowingRunnable concat( - ThrowingRunnable first, - ThrowingRunnable second - ) { + public static ThrowingRunnable concat(ThrowingRunnable first, + ThrowingRunnable second) { return () -> { first.run(); second.run(); diff --git a/src/main/java/ru/windcorp/jputil/functions/ThrowingSupplier.java b/src/main/java/ru/windcorp/jputil/functions/ThrowingSupplier.java index 84ad690..6583789 100644 --- a/src/main/java/ru/windcorp/jputil/functions/ThrowingSupplier.java +++ b/src/main/java/ru/windcorp/jputil/functions/ThrowingSupplier.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.functions; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/jputil/iterators/ArrayIterator.java b/src/main/java/ru/windcorp/jputil/iterators/ArrayIterator.java index 0b8fab2..aec4324 100644 --- a/src/main/java/ru/windcorp/jputil/iterators/ArrayIterator.java +++ b/src/main/java/ru/windcorp/jputil/iterators/ArrayIterator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.iterators; import java.util.Iterator; diff --git a/src/main/java/ru/windcorp/jputil/iterators/FunctionIterator.java b/src/main/java/ru/windcorp/jputil/iterators/FunctionIterator.java index abc5b44..e32d250 100644 --- a/src/main/java/ru/windcorp/jputil/iterators/FunctionIterator.java +++ b/src/main/java/ru/windcorp/jputil/iterators/FunctionIterator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.iterators; import java.util.Iterator; diff --git a/src/main/java/ru/windcorp/jputil/iterators/PeekingIterator.java b/src/main/java/ru/windcorp/jputil/iterators/PeekingIterator.java index 67f3da9..754e1ae 100644 --- a/src/main/java/ru/windcorp/jputil/iterators/PeekingIterator.java +++ b/src/main/java/ru/windcorp/jputil/iterators/PeekingIterator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.iterators; import java.util.Iterator; diff --git a/src/main/java/ru/windcorp/jputil/iterators/RangeIterator.java b/src/main/java/ru/windcorp/jputil/iterators/RangeIterator.java index 7da8ada..0047fa9 100644 --- a/src/main/java/ru/windcorp/jputil/iterators/RangeIterator.java +++ b/src/main/java/ru/windcorp/jputil/iterators/RangeIterator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.iterators; import java.util.Iterator; @@ -49,10 +49,8 @@ public class RangeIterator implements Iterator { public E next() { update(); if (nextIndex >= from + amount) { - throw new NoSuchElementException( - "RangeIterator about to retrieve element " + nextIndex - + " which exceeds upper boundary " + (from + amount) - ); + throw new NoSuchElementException("RangeIterator about to retrieve element " + nextIndex + + " which exceeds upper boundary " + (from + amount)); } E result = parent.next(); diff --git a/src/main/java/ru/windcorp/jputil/iterators/Reiterator.java b/src/main/java/ru/windcorp/jputil/iterators/Reiterator.java index 7969bc1..85d9122 100644 --- a/src/main/java/ru/windcorp/jputil/iterators/Reiterator.java +++ b/src/main/java/ru/windcorp/jputil/iterators/Reiterator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.iterators; import java.util.ArrayList; diff --git a/src/main/java/ru/windcorp/jputil/selectors/AbstractSelectorOperator.java b/src/main/java/ru/windcorp/jputil/selectors/AbstractSelectorOperator.java index 481e558..3448929 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/AbstractSelectorOperator.java +++ b/src/main/java/ru/windcorp/jputil/selectors/AbstractSelectorOperator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; public abstract class AbstractSelectorOperator implements SelectorOperator { diff --git a/src/main/java/ru/windcorp/jputil/selectors/NamedParameterizedSelector.java b/src/main/java/ru/windcorp/jputil/selectors/NamedParameterizedSelector.java index e0676fd..d0a7692 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/NamedParameterizedSelector.java +++ b/src/main/java/ru/windcorp/jputil/selectors/NamedParameterizedSelector.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import ru.windcorp.jputil.SyntaxException; diff --git a/src/main/java/ru/windcorp/jputil/selectors/NamedSelector.java b/src/main/java/ru/windcorp/jputil/selectors/NamedSelector.java index 196be14..7765505 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/NamedSelector.java +++ b/src/main/java/ru/windcorp/jputil/selectors/NamedSelector.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import ru.windcorp.jputil.SyntaxException; diff --git a/src/main/java/ru/windcorp/jputil/selectors/OperatorAnd.java b/src/main/java/ru/windcorp/jputil/selectors/OperatorAnd.java index 603c6d4..4b68bb6 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/OperatorAnd.java +++ b/src/main/java/ru/windcorp/jputil/selectors/OperatorAnd.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import java.util.Deque; diff --git a/src/main/java/ru/windcorp/jputil/selectors/OperatorExclude.java b/src/main/java/ru/windcorp/jputil/selectors/OperatorExclude.java index a805a2f..810f15f 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/OperatorExclude.java +++ b/src/main/java/ru/windcorp/jputil/selectors/OperatorExclude.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import java.util.Deque; diff --git a/src/main/java/ru/windcorp/jputil/selectors/OperatorNot.java b/src/main/java/ru/windcorp/jputil/selectors/OperatorNot.java index 2bf0300..b12f5dc 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/OperatorNot.java +++ b/src/main/java/ru/windcorp/jputil/selectors/OperatorNot.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import java.util.Deque; diff --git a/src/main/java/ru/windcorp/jputil/selectors/OperatorOr.java b/src/main/java/ru/windcorp/jputil/selectors/OperatorOr.java index 367e6c3..2388105 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/OperatorOr.java +++ b/src/main/java/ru/windcorp/jputil/selectors/OperatorOr.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import java.util.Deque; diff --git a/src/main/java/ru/windcorp/jputil/selectors/OperatorXor.java b/src/main/java/ru/windcorp/jputil/selectors/OperatorXor.java index 467e6a0..9b8a719 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/OperatorXor.java +++ b/src/main/java/ru/windcorp/jputil/selectors/OperatorXor.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import java.util.Deque; diff --git a/src/main/java/ru/windcorp/jputil/selectors/PredicateWrapper.java b/src/main/java/ru/windcorp/jputil/selectors/PredicateWrapper.java index 278df45..f43760a 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/PredicateWrapper.java +++ b/src/main/java/ru/windcorp/jputil/selectors/PredicateWrapper.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import java.util.function.Predicate; diff --git a/src/main/java/ru/windcorp/jputil/selectors/Selector.java b/src/main/java/ru/windcorp/jputil/selectors/Selector.java index eec8b06..450e717 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/Selector.java +++ b/src/main/java/ru/windcorp/jputil/selectors/Selector.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import java.util.function.Predicate; diff --git a/src/main/java/ru/windcorp/jputil/selectors/SelectorOperator.java b/src/main/java/ru/windcorp/jputil/selectors/SelectorOperator.java index 665d231..20b46b3 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/SelectorOperator.java +++ b/src/main/java/ru/windcorp/jputil/selectors/SelectorOperator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import java.util.Deque; diff --git a/src/main/java/ru/windcorp/jputil/selectors/SelectorSystem.java b/src/main/java/ru/windcorp/jputil/selectors/SelectorSystem.java index 0361795..a5543fe 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/SelectorSystem.java +++ b/src/main/java/ru/windcorp/jputil/selectors/SelectorSystem.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.jputil.selectors; import java.util.ArrayList; @@ -37,7 +37,7 @@ public class SelectorSystem { private final Collection> selectors = Collections.synchronizedCollection(new ArrayList>()); private final Collection operators = Collections - .synchronizedCollection(new ArrayList()); + .synchronizedCollection(new ArrayList()); private String stackPrefix = null; diff --git a/src/main/java/ru/windcorp/progressia/Progressia.java b/src/main/java/ru/windcorp/progressia/Progressia.java index db899ea..fd3529f 100644 --- a/src/main/java/ru/windcorp/progressia/Progressia.java +++ b/src/main/java/ru/windcorp/progressia/Progressia.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia; public class Progressia { diff --git a/src/main/java/ru/windcorp/progressia/ProgressiaLauncher.java b/src/main/java/ru/windcorp/progressia/ProgressiaLauncher.java index c8935fc..08ce1e9 100644 --- a/src/main/java/ru/windcorp/progressia/ProgressiaLauncher.java +++ b/src/main/java/ru/windcorp/progressia/ProgressiaLauncher.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia; import ru.windcorp.progressia.common.util.crash.CrashReports; diff --git a/src/main/java/ru/windcorp/progressia/Proxy.java b/src/main/java/ru/windcorp/progressia/Proxy.java index a1af080..8b5542e 100644 --- a/src/main/java/ru/windcorp/progressia/Proxy.java +++ b/src/main/java/ru/windcorp/progressia/Proxy.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia; public interface Proxy { diff --git a/src/main/java/ru/windcorp/progressia/client/Client.java b/src/main/java/ru/windcorp/progressia/client/Client.java index d8800c7..3121602 100644 --- a/src/main/java/ru/windcorp/progressia/client/Client.java +++ b/src/main/java/ru/windcorp/progressia/client/Client.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client; import ru.windcorp.progressia.client.comms.DefaultClientCommsListener; @@ -24,7 +24,7 @@ import ru.windcorp.progressia.client.graphics.world.Camera; import ru.windcorp.progressia.client.graphics.world.EntityAnchor; import ru.windcorp.progressia.client.graphics.world.LocalPlayer; import ru.windcorp.progressia.client.world.WorldRender; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.entity.EntityData; public class Client { @@ -36,7 +36,7 @@ public class Client { private final ServerCommsChannel comms; - public Client(WorldData world, ServerCommsChannel comms) { + public Client(DefaultWorldData world, ServerCommsChannel comms) { this.world = new WorldRender(world, this); this.comms = comms; @@ -69,11 +69,7 @@ public class Client { return; } - getCamera().setAnchor( - new EntityAnchor( - getWorld().getEntityRenderable(entity) - ) - ); + getCamera().setAnchor(new EntityAnchor(getWorld().getEntityRenderable(entity))); } } diff --git a/src/main/java/ru/windcorp/progressia/client/ClientProxy.java b/src/main/java/ru/windcorp/progressia/client/ClientProxy.java index 1d154e7..c7a221e 100644 --- a/src/main/java/ru/windcorp/progressia/client/ClientProxy.java +++ b/src/main/java/ru/windcorp/progressia/client/ClientProxy.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client; import ru.windcorp.progressia.Proxy; @@ -42,10 +42,8 @@ public class ClientProxy implements Proxy { try { RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init); RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init); - RenderTaskQueue.waitAndInvoke( - () -> Typefaces - .setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz"))) - ); + RenderTaskQueue.waitAndInvoke(() -> Typefaces + .setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))); } catch (InterruptedException e) { throw CrashReports.report(e, "ClientProxy failed"); } @@ -60,7 +58,7 @@ public class ClientProxy implements Proxy { ServerState.startServer(); ClientState.connectToLocalServer(); - + TestMusicPlayer.start(); } diff --git a/src/main/java/ru/windcorp/progressia/client/ClientState.java b/src/main/java/ru/windcorp/progressia/client/ClientState.java index 75f0f07..91d21a7 100644 --- a/src/main/java/ru/windcorp/progressia/client/ClientState.java +++ b/src/main/java/ru/windcorp/progressia/client/ClientState.java @@ -15,13 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client; import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel; import ru.windcorp.progressia.client.graphics.GUI; import ru.windcorp.progressia.client.graphics.world.LayerWorld; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.server.ServerState; import ru.windcorp.progressia.test.LayerAbout; import ru.windcorp.progressia.test.LayerTestUI; @@ -41,11 +41,9 @@ public class ClientState { public static void connectToLocalServer() { - WorldData world = new WorldData(); + DefaultWorldData world = new DefaultWorldData(); - LocalServerCommsChannel channel = new LocalServerCommsChannel( - ServerState.getInstance() - ); + LocalServerCommsChannel channel = new LocalServerCommsChannel(ServerState.getInstance()); Client client = new Client(world, channel); diff --git a/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java b/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java index bb0482d..d578c85 100644 --- a/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java +++ b/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client; import ru.windcorp.progressia.ProgressiaLauncher; diff --git a/src/main/java/ru/windcorp/progressia/client/audio/AudioFormat.java b/src/main/java/ru/windcorp/progressia/client/audio/AudioFormat.java index 848e66c..cade47d 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/AudioFormat.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/AudioFormat.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.audio; public enum AudioFormat { diff --git a/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java b/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java index 49f2312..a7ddd32 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.audio; import org.lwjgl.openal.*; @@ -43,10 +43,7 @@ public class AudioManager { private static Speaker musicSpeaker; public static void initAL() { - String defaultDeviceName = alcGetString( - 0, - ALC_DEFAULT_DEVICE_SPECIFIER - ); + String defaultDeviceName = alcGetString(0, ALC_DEFAULT_DEVICE_SPECIFIER); device = alcOpenDevice(defaultDeviceName); @@ -75,10 +72,7 @@ public class AudioManager { lastSoundIndex = 0; } speaker = soundSpeakers.get(lastSoundIndex); - } while ( - speaker.getState() - .equals(Speaker.State.PLAYING_LOOP) - ); + } while (speaker.getState().equals(Speaker.State.PLAYING_LOOP)); return speaker; } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/AudioRegistry.java b/src/main/java/ru/windcorp/progressia/client/audio/AudioRegistry.java index 3199622..2f1da30 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/AudioRegistry.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/AudioRegistry.java @@ -21,9 +21,9 @@ import ru.windcorp.progressia.client.audio.backend.SoundType; import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; public class AudioRegistry extends NamespacedInstanceRegistry { - + private static final AudioRegistry INSTANCE = new AudioRegistry(); - + /** * @return the instance */ diff --git a/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java b/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java index 24cc2de..a4cab80 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.audio; import ru.windcorp.progressia.common.resource.ResourceManager; @@ -29,10 +29,7 @@ public class AudioSystem { } static void loadAudioData() { - AudioManager.loadSound( - ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"), - "Progressia:BlockDestroy", - AudioFormat.MONO - ); + AudioManager.loadSound(ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"), + "Progressia:BlockDestroy", AudioFormat.MONO); } } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/Music.java b/src/main/java/ru/windcorp/progressia/client/audio/Music.java index 031b58e..d60860a 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/Music.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/Music.java @@ -15,18 +15,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.audio; import glm.vec._3.Vec3; import ru.windcorp.progressia.client.audio.backend.SoundType; import ru.windcorp.progressia.client.audio.backend.Speaker; -public class Music - extends Sound { - - - +public class Music extends Sound { + public Music(SoundType soundType, int timeLength, float pitch, float gain) { super(soundType, timeLength, new Vec3(), new Vec3(), pitch, gain); } @@ -47,7 +44,7 @@ public class Music protected Speaker initSpeaker() { return AudioManager.initMusicSpeaker(soundType); } - + @Override public void setPosition(Vec3 position) { throw new UnsupportedOperationException(); diff --git a/src/main/java/ru/windcorp/progressia/client/audio/Sound.java b/src/main/java/ru/windcorp/progressia/client/audio/Sound.java index 77f0c9e..a45b535 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/Sound.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/Sound.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.audio; import glm.vec._3.Vec3; @@ -29,9 +29,9 @@ public class Sound { protected float pitch = 1.0f; protected float gain = 1.0f; protected int timeLength = 0; - + protected SoundType soundType; - + public Sound(SoundType soundType) { this.soundType = soundType; } @@ -39,37 +39,23 @@ public class Sound { public Sound(String id) { this(AudioRegistry.getInstance().get(id)); } - - public Sound( - String id, - int timeLength, - Vec3 position, - Vec3 velocity, - float pitch, - float gain - ) { + + public Sound(String id, int timeLength, Vec3 position, Vec3 velocity, float pitch, float gain) { this(id); this.position = position; this.velocity = velocity; this.pitch = pitch; this.gain = gain; } - - public Sound( - SoundType soundType, - int timeLength, - Vec3 position, - Vec3 velocity, - float pitch, - float gain - ) { + + public Sound(SoundType soundType, int timeLength, Vec3 position, Vec3 velocity, float pitch, float gain) { this(soundType); this.position = position; this.velocity = velocity; this.pitch = pitch; this.gain = gain; } - + protected Speaker initSpeaker() { return AudioManager.initSpeaker(soundType); } @@ -119,7 +105,7 @@ public class Sound { public float getPitch() { return pitch; } - + public double getDuration() { return soundType.getDuration(); } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java index 9fa48e0..27e77b8 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.audio.backend; import org.lwjgl.BufferUtils; @@ -39,12 +39,7 @@ public class AudioReader { ShortBuffer rawAudio = decodeVorbis(resource, channelBuffer, rateBuffer); - return new SoundType( - id, - rawAudio, - format, - rateBuffer.get(0) - ); + return new SoundType(id, rawAudio, format, rateBuffer.get(0)); } public static SoundType readAsMono(Resource resource, String id) { @@ -55,15 +50,7 @@ public class AudioReader { return readAsSpecified(resource, id, AL_FORMAT_STEREO16); } - private static ShortBuffer decodeVorbis( - Resource dataToDecode, - IntBuffer channelsBuffer, - IntBuffer rateBuffer - ) { - return stb_vorbis_decode_memory( - dataToDecode.readAsBytes(), - channelsBuffer, - rateBuffer - ); + private static ShortBuffer decodeVorbis(Resource dataToDecode, IntBuffer channelsBuffer, IntBuffer rateBuffer) { + return stb_vorbis_decode_memory(dataToDecode.readAsBytes(), channelsBuffer, rateBuffer); } } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/Listener.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/Listener.java index 8f6fe35..78a9c9a 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/Listener.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/Listener.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.audio.backend; import glm.vec._3.Vec3; @@ -55,9 +55,8 @@ public class Listener { if (isInWorld) { if (wasInWorld) { - velocity.set(camera.getLastAnchorPosition()).sub(position).div( - (float) GraphicsInterface.getFrameLength() - ); + velocity.set(camera.getLastAnchorPosition()).sub(position) + .div((float) GraphicsInterface.getFrameLength()); } else { // If !wasInWorld, previous position is nonsence. Assume 0. velocity.set(0); @@ -72,9 +71,9 @@ public class Listener { } /* - * Only apply if there is a chance that params changed. - * This can only happen if we are in world now (isInWorld) or we just - * left world (wasInWorld, then we need to reset). + * Only apply if there is a chance that params changed. This can only + * happen if we are in world now (isInWorld) or we just left world + * (wasInWorld, then we need to reset). */ if (isInWorld || wasInWorld) { applyParams(); @@ -91,17 +90,7 @@ public class Listener { private void applyParams() { alListener3f(AL_POSITION, position.x, position.y, position.z); alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z); - alListenerfv( - AL_ORIENTATION, - new float[] { - oriAt.x, - oriAt.y, - oriAt.z, - oriUp.x, - oriUp.y, - oriUp.z - } - ); + alListenerfv(AL_ORIENTATION, new float[] { oriAt.x, oriAt.y, oriAt.z, oriUp.x, oriUp.y, oriUp.z }); } } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java index cdb1954..fa7d5a0 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.audio.backend; import ru.windcorp.progressia.common.util.namespaces.Namespaced; @@ -34,12 +34,7 @@ public class SoundType extends Namespaced { private int audioBuffer; private double duration; - public SoundType( - String id, - ShortBuffer rawAudio, - int format, - int sampleRate - ) { + public SoundType(String id, ShortBuffer rawAudio, int format, int sampleRate) { super(id); this.rawAudio = rawAudio; this.sampleRate = sampleRate; @@ -56,7 +51,7 @@ public class SoundType extends Namespaced { public void initSpeaker(Speaker speaker) { speaker.setAudioData(audioBuffer); } - + public double getDuration() { return duration; } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java index c649a6a..6e7af4b 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.audio.backend; import glm.vec._3.Vec3; @@ -24,9 +24,7 @@ import static org.lwjgl.openal.AL11.*; public class Speaker { public enum State { - NOT_PLAYING, - PLAYING, - PLAYING_LOOP + NOT_PLAYING, PLAYING, PLAYING_LOOP } // Buffers @@ -49,13 +47,7 @@ public class Speaker { setAudioData(audioData); } - public Speaker( - int audioData, - Vec3 position, - Vec3 velocity, - float pitch, - float gain - ) { + public Speaker(int audioData, Vec3 position, Vec3 velocity, float pitch, float gain) { setAudioData(audioData); setPosition(position); setVelocity(velocity); @@ -63,12 +55,7 @@ public class Speaker { setGain(gain); } - public Speaker( - Vec3 position, - Vec3 velocity, - float pitch, - float gain - ) { + public Speaker(Vec3 position, Vec3 velocity, float pitch, float gain) { setPosition(position); setVelocity(velocity); setPitch(pitch); diff --git a/src/main/java/ru/windcorp/progressia/client/comms/DefaultClientCommsListener.java b/src/main/java/ru/windcorp/progressia/client/comms/DefaultClientCommsListener.java index dad05fd..e983e51 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/DefaultClientCommsListener.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/DefaultClientCommsListener.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms; import java.io.IOException; @@ -39,9 +39,7 @@ public class DefaultClientCommsListener implements CommsListener { @Override public void onPacketReceived(Packet packet) { if (packet instanceof PacketAffectWorld) { - ((PacketAffectWorld) packet).apply( - getClient().getWorld().getData() - ); + ((PacketAffectWorld) packet).apply(getClient().getWorld().getData()); } else if (packet instanceof PacketSetLocalPlayer) { setLocalPlayer((PacketSetLocalPlayer) packet); } diff --git a/src/main/java/ru/windcorp/progressia/client/comms/ServerCommsChannel.java b/src/main/java/ru/windcorp/progressia/client/comms/ServerCommsChannel.java index 3a0a1b1..6bf9a8e 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/ServerCommsChannel.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/ServerCommsChannel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms; import ru.windcorp.progressia.common.comms.CommsChannel; diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTrigger.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTrigger.java index 88e9fa3..0f0e091 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTrigger.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTrigger.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms.controls; import ru.windcorp.progressia.common.util.namespaces.Namespaced; diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerInputBased.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerInputBased.java index b2f8de4..f1985b3 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerInputBased.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerInputBased.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms.controls; import ru.windcorp.progressia.client.graphics.input.InputEvent; diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java index 22004b8..476c482 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms.controls; import java.util.function.BiConsumer; @@ -33,17 +33,12 @@ public class ControlTriggerLambda extends ControlTriggerInputBased { private final Predicate predicate; private final BiConsumer dataWriter; - public ControlTriggerLambda( - String id, - Predicate predicate, - BiConsumer dataWriter - ) { + public ControlTriggerLambda(String id, Predicate predicate, + BiConsumer dataWriter) { super(id); - this.packetId = NamespacedUtil.getId( - NamespacedUtil.getNamespace(id), - "ControlKeyPress" + NamespacedUtil.getName(id) - ); + this.packetId = NamespacedUtil.getId(NamespacedUtil.getNamespace(id), + "ControlKeyPress" + NamespacedUtil.getName(id)); this.predicate = predicate; this.dataWriter = dataWriter; @@ -54,10 +49,7 @@ public class ControlTriggerLambda extends ControlTriggerInputBased { if (!predicate.test(event)) return null; - PacketControl packet = new PacketControl( - packetId, - ControlDataRegistry.getInstance().create(getId()) - ); + PacketControl packet = new PacketControl(packetId, ControlDataRegistry.getInstance().create(getId())); dataWriter.accept(event, packet.getControl()); diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLocalLambda.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLocalLambda.java index b2ae739..7708328 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLocalLambda.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLocalLambda.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms.controls; import java.util.function.Consumer; @@ -29,11 +29,7 @@ public class ControlTriggerLocalLambda extends ControlTriggerInputBased { private final Predicate predicate; private final Consumer action; - public ControlTriggerLocalLambda( - String id, - Predicate predicate, - Consumer action - ) { + public ControlTriggerLocalLambda(String id, Predicate predicate, Consumer action) { super(id); this.predicate = predicate; diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerRegistry.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerRegistry.java index a2ec71e..5a3f4a9 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerRegistry.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms.controls; import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java index 2c0d61d..260e220 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms.controls; import java.util.function.BiConsumer; @@ -27,122 +27,59 @@ import ru.windcorp.progressia.common.comms.controls.ControlData; public class ControlTriggers { - public static ControlTriggerInputBased of( - String id, - BiConsumer dataWriter, - Predicate predicate - ) { + public static ControlTriggerInputBased of(String id, BiConsumer dataWriter, + Predicate predicate) { return new ControlTriggerLambda(id, predicate, dataWriter); } - public static ControlTriggerInputBased of( - String id, - Consumer dataWriter, - Predicate predicate - ) { - return of( - id, - (input, control) -> dataWriter.accept(control), - predicate - ); + public static ControlTriggerInputBased of(String id, Consumer dataWriter, + Predicate predicate) { + return of(id, (input, control) -> dataWriter.accept(control), predicate); } - public static ControlTriggerInputBased of( - String id, - Predicate predicate - ) { - return of( - id, - (input, control) -> { - }, - predicate - ); + public static ControlTriggerInputBased of(String id, Predicate predicate) { + return of(id, (input, control) -> { + }, predicate); } @SafeVarargs - public static ControlTriggerInputBased of( - String id, - Class inputType, - BiConsumer dataWriter, - Predicate... predicates - ) { - return of( - id, - createCheckedDataWriter(inputType, dataWriter), - createCheckedCompoundPredicate(inputType, predicates) - ); + public static ControlTriggerInputBased of(String id, Class inputType, + BiConsumer dataWriter, Predicate... predicates) { + return of(id, createCheckedDataWriter(inputType, dataWriter), + createCheckedCompoundPredicate(inputType, predicates)); } @SafeVarargs - public static ControlTriggerInputBased of( - String id, - Class inputType, - Consumer dataWriter, - Predicate... predicates - ) { - return of( - id, - inputType, - (input, control) -> dataWriter.accept(control), - predicates - ); + public static ControlTriggerInputBased of(String id, Class inputType, + Consumer dataWriter, Predicate... predicates) { + return of(id, inputType, (input, control) -> dataWriter.accept(control), predicates); } @SafeVarargs - public static ControlTriggerInputBased of( - String id, - Class inputType, - Predicate... predicates - ) { - return of( - id, - (input, control) -> { - }, - createCheckedCompoundPredicate(inputType, predicates) - ); + public static ControlTriggerInputBased of(String id, Class inputType, + Predicate... predicates) { + return of(id, (input, control) -> { + }, createCheckedCompoundPredicate(inputType, predicates)); } @SafeVarargs - public static ControlTriggerInputBased of( - String id, - BiConsumer dataWriter, - Predicate... predicates - ) { - return of( - id, - InputEvent.class, - dataWriter, - predicates - ); + public static ControlTriggerInputBased of(String id, BiConsumer dataWriter, + Predicate... predicates) { + return of(id, InputEvent.class, dataWriter, predicates); } @SafeVarargs - public static ControlTriggerInputBased of( - String id, - Consumer dataWriter, - Predicate... predicates - ) { - return of( - id, - (input, control) -> dataWriter.accept(control), - predicates - ); + public static ControlTriggerInputBased of(String id, Consumer dataWriter, + Predicate... predicates) { + return of(id, (input, control) -> dataWriter.accept(control), predicates); } @SafeVarargs - public static ControlTriggerInputBased of( - String id, - Predicate... predicates - ) { - return of( - id, - InputEvent.class, - (input, control) -> { - }, - predicates - ); + public static ControlTriggerInputBased of(String id, Predicate... predicates) { + return of(id, InputEvent.class, (input, control) -> { + }, predicates); } - + // // /// @@ -156,101 +93,53 @@ public class ControlTriggers { // // // - - public static ControlTriggerInputBased localOf( - String id, - Consumer action, - Predicate predicate - ) { + + public static ControlTriggerInputBased localOf(String id, Consumer action, + Predicate predicate) { return new ControlTriggerLocalLambda(id, predicate, action); } - public static ControlTriggerInputBased localOf( - String id, - Runnable action, - Predicate predicate - ) { - return localOf( - id, - input -> action.run(), - predicate - ); + public static ControlTriggerInputBased localOf(String id, Runnable action, Predicate predicate) { + return localOf(id, input -> action.run(), predicate); } @SafeVarargs - public static ControlTriggerInputBased localOf( - String id, - Class inputType, - Consumer action, - Predicate... predicates - ) { - return localOf( - id, - createCheckedAction(inputType, action), - createCheckedCompoundPredicate(inputType, predicates) - ); + public static ControlTriggerInputBased localOf(String id, Class inputType, + Consumer action, Predicate... predicates) { + return localOf(id, createCheckedAction(inputType, action), + createCheckedCompoundPredicate(inputType, predicates)); } @SafeVarargs - public static ControlTriggerInputBased localOf( - String id, - Class inputType, - Runnable action, - Predicate... predicates - ) { - return localOf( - id, - inputType, - input -> action.run(), - predicates - ); + public static ControlTriggerInputBased localOf(String id, Class inputType, + Runnable action, Predicate... predicates) { + return localOf(id, inputType, input -> action.run(), predicates); } @SafeVarargs - public static ControlTriggerInputBased localOf( - String id, - Consumer action, - Predicate... predicates - ) { - return localOf( - id, - InputEvent.class, - action, - predicates - ); + public static ControlTriggerInputBased localOf(String id, Consumer action, + Predicate... predicates) { + return localOf(id, InputEvent.class, action, predicates); } @SafeVarargs - public static ControlTriggerInputBased localOf( - String id, - Runnable action, - Predicate... predicates - ) { - return of( - id, - input -> action.run(), - predicates - ); + public static ControlTriggerInputBased localOf(String id, Runnable action, + Predicate... predicates) { + return of(id, input -> action.run(), predicates); } private static BiConsumer createCheckedDataWriter( - Class inputType, - BiConsumer dataWriter - ) { + Class inputType, BiConsumer dataWriter) { return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control); } - - private static Consumer createCheckedAction( - Class inputType, - Consumer action - ) { + + private static Consumer createCheckedAction(Class inputType, + Consumer action) { return inputEvent -> action.accept(inputType.cast(inputEvent)); } - private static Predicate createCheckedCompoundPredicate( - Class inputType, - Predicate[] predicates - ) { + private static Predicate createCheckedCompoundPredicate(Class inputType, + Predicate[] predicates) { return new CompoundCastPredicate<>(inputType, predicates); } diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/InputBasedControls.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/InputBasedControls.java index 28b9e1b..2fbd086 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/InputBasedControls.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/InputBasedControls.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms.controls; import ru.windcorp.progressia.client.Client; @@ -32,8 +32,7 @@ public class InputBasedControls { this.client = client; this.controls = ControlTriggerRegistry.getInstance().values().stream() - .filter(ControlTriggerInputBased.class::isInstance) - .toArray(ControlTriggerInputBased[]::new); + .filter(ControlTriggerInputBased.class::isInstance).toArray(ControlTriggerInputBased[]::new); } public void handleInput(Input input) { diff --git a/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalClient.java b/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalClient.java index 816fba8..9fc0e47 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalClient.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalClient.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms.localhost; import java.io.IOException; diff --git a/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalServerCommsChannel.java b/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalServerCommsChannel.java index 194a2a1..14ec90a 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalServerCommsChannel.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalServerCommsChannel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.comms.localhost; import ru.windcorp.progressia.client.comms.ServerCommsChannel; @@ -34,11 +34,7 @@ public class LocalServerCommsChannel extends ServerCommsChannel { public void connect(String login) { setState(State.CONNECTED); - this.localClient = new LocalClient( - server.getClientManager().grabClientId(), - login, - this - ); + this.localClient = new LocalClient(server.getClientManager().grabClientId(), login, this); server.getClientManager().addClient(localClient); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java b/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java index bb4d85b..38e405f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics; import java.util.ArrayList; @@ -43,7 +43,7 @@ public class GUI { } private static final List MODIFICATION_QUEUE = Collections - .synchronizedList(new ArrayList<>()); + .synchronizedList(new ArrayList<>()); private static class ModifiableInput extends Input { @Override diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java b/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java index dfa72d5..b7ef5b4 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/FaceCulling.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/FaceCulling.java index 61645f4..bdab268 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/FaceCulling.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/FaceCulling.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import java.util.ArrayDeque; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java index 1635c7a..879f54b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import glm.vec._2.i.Vec2i; @@ -61,7 +61,7 @@ public class GraphicsBackend { static void setOpenGLInitialized(boolean isOpenGLInitialized) { GraphicsBackend.isOpenGLInitialized = isOpenGLInitialized; } - + public static void initialize() { startRenderThread(); } @@ -159,27 +159,14 @@ public class GraphicsBackend { public static void setFullscreen() { GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor()); - glfwSetWindowMonitor( - getWindowHandle(), - glfwGetPrimaryMonitor(), - 0, - 0, - vidmode.width(), - vidmode.height(), - 0); + glfwSetWindowMonitor(getWindowHandle(), glfwGetPrimaryMonitor(), 0, 0, vidmode.width(), vidmode.height(), 0); isFullscreen = true; } public static void setWindowed() { GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor()); - glfwSetWindowMonitor( - getWindowHandle(), - 0, - (vidmode.width() - getFrameWidth()) / 2, - (vidmode.height() - getFrameHeight()) / 2, - getFrameWidth(), - getFrameHeight(), - 0); + glfwSetWindowMonitor(getWindowHandle(), 0, (vidmode.width() - getFrameWidth()) / 2, + (vidmode.height() - getFrameHeight()) / 2, getFrameWidth(), getFrameHeight(), 0); isFullscreen = false; } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java index ffd0b49..ffe0add 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import glm.vec._2.i.Vec2i; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputHandler.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputHandler.java index 34d936c..2dcbd44 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputHandler.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputHandler.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import org.lwjgl.glfw.GLFW; @@ -49,13 +49,7 @@ public class InputHandler { private static final ModifiableKeyEvent THE_KEY_EVENT = new ModifiableKeyEvent(); - static void handleKeyInput( - long window, - int key, - int scancode, - int action, - int mods - ) { + static void handleKeyInput(long window, int key, int scancode, int action, int mods) { if (GraphicsBackend.getWindowHandle() != window) return; THE_KEY_EVENT.initialize(key, scancode, action, mods); @@ -71,12 +65,7 @@ public class InputHandler { } } - static void handleMouseButtonInput( - long window, - int key, - int action, - int mods - ) { + static void handleMouseButtonInput(long window, int key, int action, int mods) { handleKeyInput(window, key, Integer.MAX_VALUE - key, action, mods); } @@ -97,11 +86,7 @@ public class InputHandler { private static final ModifiableCursorMoveEvent THE_CURSOR_MOVE_EVENT = new ModifiableCursorMoveEvent(); - static void handleMouseMoveInput( - long window, - double x, - double y - ) { + static void handleMouseMoveInput(long window, double x, double y) { if (GraphicsBackend.getWindowHandle() != window) return; y = GraphicsInterface.getFrameHeight() - y; // Flip y axis @@ -131,11 +116,7 @@ public class InputHandler { private static final ModifiableWheelScrollEvent THE_WHEEL_SCROLL_EVENT = new ModifiableWheelScrollEvent(); - static void handleWheelScroll( - long window, - double xoffset, - double yoffset - ) { + static void handleWheelScroll(long window, double xoffset, double yoffset) { if (GraphicsBackend.getWindowHandle() != window) return; THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset); @@ -162,10 +143,7 @@ public class InputHandler { /* * NB: this is NOT a GLFW callback, the raw callback is in GraphicsBackend */ - static void handleFrameResize( - int width, - int height - ) { + static void handleFrameResize(int width, int height) { THE_FRAME_RESIZE_EVENT.initialize(width, height); dispatch(THE_FRAME_RESIZE_EVENT); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputTracker.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputTracker.java index 29dec99..8e7e86c 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputTracker.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputTracker.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import glm.vec._2.d.Vec2d; @@ -24,10 +24,7 @@ import gnu.trove.set.hash.TIntHashSet; public class InputTracker { - private static final Vec2d CURSOR_POSITION = new Vec2d( - Double.NaN, - Double.NaN - ); + private static final Vec2d CURSOR_POSITION = new Vec2d(Double.NaN, Double.NaN); private static final TIntSet PRESSED_KEYS = new TIntHashSet(256); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java index 9239150..6664266 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import static org.lwjgl.opengl.GL11.*; @@ -66,7 +66,7 @@ class LWJGLInitializer { GraphicsBackend.setWindowHandle(handle); glfwMakeContextCurrent(handle); - glfwSwapInterval(0); // TODO: remove after config system is added + glfwSwapInterval(0); // TODO: remove after config system is added } private static void positionWindow() { @@ -92,16 +92,10 @@ class LWJGLInitializer { private static void setupWindowCallbacks() { long handle = GraphicsBackend.getWindowHandle(); - glfwSetFramebufferSizeCallback( - handle, - GraphicsBackend::onFrameResized - ); + glfwSetFramebufferSizeCallback(handle, GraphicsBackend::onFrameResized); glfwSetKeyCallback(handle, InputHandler::handleKeyInput); - glfwSetMouseButtonCallback( - handle, - InputHandler::handleMouseButtonInput - ); + glfwSetMouseButtonCallback(handle, InputHandler::handleMouseButtonInput); glfwSetCursorPosCallback(handle, InputHandler::handleMouseMoveInput); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/OpenGLObjectTracker.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/OpenGLObjectTracker.java index c467d45..a62a32f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/OpenGLObjectTracker.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/OpenGLObjectTracker.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import java.lang.ref.PhantomReference; @@ -34,19 +34,13 @@ public class OpenGLObjectTracker { private static final ReferenceQueue DELETE_QUEUE = new ReferenceQueue<>(); public synchronized static void register(OpenGLDeletable object, IntConsumer glDeleter) { - GLPhantomReference glRef = new GLPhantomReference<>( - object, - DELETE_QUEUE, - object.getHandle(), - glDeleter - ); + GLPhantomReference glRef = new GLPhantomReference<>(object, DELETE_QUEUE, object.getHandle(), + glDeleter); TO_DELETE.add(glRef); } public static void deleteAllObjects() { - for ( - GLPhantomReference glRef : TO_DELETE - ) { + for (GLPhantomReference glRef : TO_DELETE) { glRef.clear(); } } @@ -75,20 +69,16 @@ public class OpenGLObjectTracker { * It is possible to create a phantom reference with a {@code null} * queue, but such a reference is completely useless: Its {@code get} * method will always return {@code null} and, since it does not have a - * queue, - * it will never be enqueued. + * queue, it will never be enqueued. * - * @param referent the object the new phantom reference will refer to - * @param q the queue with which the reference is to be - * registered, - * or {@code null} if registration is not required + * @param referent + * the object the new phantom reference will refer to + * @param q + * the queue with which the reference is to be registered, or + * {@code null} if registration is not required */ - public GLPhantomReference( - T referent, - ReferenceQueue q, - int referentGLhandle, - IntConsumer GLDeleter - ) { + public GLPhantomReference(T referent, ReferenceQueue q, int referentGLhandle, + IntConsumer GLDeleter) { super(referent, q); this.referentGLhandle = referentGLhandle; this.GLDeleter = GLDeleter; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderTaskQueue.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderTaskQueue.java index 0a1d722..5c8d260 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderTaskQueue.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderTaskQueue.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import ru.windcorp.jputil.functions.ThrowingRunnable; @@ -41,11 +41,7 @@ public class RenderTaskQueue { HANDLER.invokeNow(task); } - public static void waitAndInvoke( - ThrowingRunnable task - ) - throws InterruptedException, - E { + public static void waitAndInvoke(ThrowingRunnable task) throws InterruptedException, E { HANDLER.waitAndInvoke(task); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderThread.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderThread.java index 47d4306..d92385e 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderThread.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderThread.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import static org.lwjgl.glfw.GLFW.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/Usage.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/Usage.java index 8a526c1..dc3199d 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/Usage.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/Usage.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import static org.lwjgl.opengl.GL15.GL_DYNAMIC_DRAW; @@ -23,9 +23,7 @@ import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW; import static org.lwjgl.opengl.GL15.GL_STREAM_DRAW; public enum Usage { // TODO add _COPY and _READ, pref. as another enum - STATIC(GL_STATIC_DRAW), - DYNAMIC(GL_DYNAMIC_DRAW), - STREAM(GL_STREAM_DRAW); + STATIC(GL_STATIC_DRAW), DYNAMIC(GL_DYNAMIC_DRAW), STREAM(GL_STREAM_DRAW); private final int glCode; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/VertexBufferObject.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/VertexBufferObject.java index 7fe23f7..ad81138 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/VertexBufferObject.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/VertexBufferObject.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend; import static org.lwjgl.opengl.GL20.*; @@ -28,8 +28,7 @@ import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGL public class VertexBufferObject implements OpenGLDeletable { public static enum BindTarget { - ARRAY(GL_ARRAY_BUFFER), - ELEMENT_ARRAY(GL_ELEMENT_ARRAY_BUFFER); + ARRAY(GL_ARRAY_BUFFER), ELEMENT_ARRAY(GL_ELEMENT_ARRAY_BUFFER); private final int glCode; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/CombinedShader.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/CombinedShader.java index 63fb4c9..754efba 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/CombinedShader.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/CombinedShader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders; import ru.windcorp.progressia.common.resource.Resource; @@ -32,12 +32,7 @@ public class CombinedShader extends Shader { for (int i = 1; i < resources.length; ++i) { if (ShaderType.guessByResourceName(resources[i]) != first) { throw new IllegalArgumentException( - "Deduced shader types of " - + resources[0] - + " and " - + resources[i] - + " differ" - ); + "Deduced shader types of " + resources[0] + " and " + resources[i] + " differ"); } } @@ -71,19 +66,8 @@ public class CombinedShader extends Shader { if (contents.codePointAt(versionIndex) == '#') { final String versionAnnotation = "#version "; - if ( - contents.regionMatches( - versionIndex, - versionAnnotation, - 0, - versionAnnotation.length() - ) - ) { - contents = contents.substring( - versionIndex - + versionAnnotation.length() - + "120".length() - ); + if (contents.regionMatches(versionIndex, versionAnnotation, 0, versionAnnotation.length())) { + contents = contents.substring(versionIndex + versionAnnotation.length() + "120".length()); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Program.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Program.java index 98d512e..b980c21 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Program.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Program.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders; import static org.lwjgl.opengl.GL11.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Shader.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Shader.java index 714fd1a..8851f66 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Shader.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Shader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders; import static org.lwjgl.opengl.GL11.*; @@ -57,10 +57,7 @@ public class Shader implements OpenGLDeletable { if (resource.contains("fsh")) return FRAGMENT; - throw new IllegalArgumentException( - "Cannot deduce shader type from resource name \"" + - resource + "\"" - ); + throw new IllegalArgumentException("Cannot deduce shader type from resource name \"" + resource + "\""); } } @@ -90,10 +87,7 @@ public class Shader implements OpenGLDeletable { } public Shader(String resource) { - this( - ShaderType.guessByResourceName(resource), - getShaderResource(resource).readAsString() - ); + this(ShaderType.guessByResourceName(resource), getShaderResource(resource).readAsString()); } @Override diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/Attribute.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/Attribute.java index d56210a..028a0b3 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/Attribute.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/Attribute.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.attributes; import ru.windcorp.progressia.client.graphics.backend.shaders.Program; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/AttributeVertexArray.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/AttributeVertexArray.java index 2ca192d..b380540 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/AttributeVertexArray.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/AttributeVertexArray.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.attributes; import static org.lwjgl.opengl.GL11.*; @@ -51,104 +51,29 @@ public class AttributeVertexArray extends Attribute { } } - public void set( - int size, - boolean normalized, - int stride, - ByteBuffer pointer - ) { - glVertexAttribPointer( - handle, - size, - GL_BYTE, - normalized, - stride, - pointer - ); + public void set(int size, boolean normalized, int stride, ByteBuffer pointer) { + glVertexAttribPointer(handle, size, GL_BYTE, normalized, stride, pointer); } - public void set( - int size, - boolean normalized, - int stride, - FloatBuffer pointer - ) { - glVertexAttribPointer( - handle, - size, - GL_FLOAT, - normalized, - stride, - pointer - ); + public void set(int size, boolean normalized, int stride, FloatBuffer pointer) { + glVertexAttribPointer(handle, size, GL_FLOAT, normalized, stride, pointer); } - public void set( - int size, - boolean normalized, - int stride, - IntBuffer pointer - ) { - glVertexAttribPointer( - handle, - size, - GL_INT, - normalized, - stride, - pointer - ); + public void set(int size, boolean normalized, int stride, IntBuffer pointer) { + glVertexAttribPointer(handle, size, GL_INT, normalized, stride, pointer); } - public void set( - int size, - boolean normalized, - int stride, - ShortBuffer pointer - ) { - glVertexAttribPointer( - handle, - size, - GL_SHORT, - normalized, - stride, - pointer - ); + public void set(int size, boolean normalized, int stride, ShortBuffer pointer) { + glVertexAttribPointer(handle, size, GL_SHORT, normalized, stride, pointer); } - public void set( - int size, - int type, - boolean normalized, - int stride, - long pointer - ) { - glVertexAttribPointer( - handle, - size, - type, - normalized, - stride, - pointer - ); + public void set(int size, int type, boolean normalized, int stride, long pointer) { + glVertexAttribPointer(handle, size, type, normalized, stride, pointer); } - public void set( - int size, - int type, - boolean normalized, - int stride, - VertexBufferObject vbo, - long offset - ) { + public void set(int size, int type, boolean normalized, int stride, VertexBufferObject vbo, long offset) { glBindBuffer(GL_ARRAY_BUFFER, vbo.getHandle()); - glVertexAttribPointer( - handle, - size, - type, - normalized, - stride, - offset - ); + glVertexAttribPointer(handle, size, type, normalized, stride, offset); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform.java index 8de5f1c..aa09d49 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import ru.windcorp.progressia.client.graphics.backend.shaders.Program; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Float.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Float.java index 6e2a62b..b41e313 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Float.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Float.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Int.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Int.java index 79d14a0..6389583 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Int.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Int.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Float.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Float.java index 166f47b..1c609c2 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Float.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Float.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Int.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Int.java index d8dde9b..679de9d 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Int.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Int.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Matrix.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Matrix.java index 6bbc3a9..b45c598 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Matrix.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Matrix.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Float.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Float.java index 21ea95b..d381a14 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Float.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Float.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Int.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Int.java index 1eb4690..283c459 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Int.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Int.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Matrix.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Matrix.java index 255fe2a..f2a0c12 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Matrix.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Matrix.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Float.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Float.java index daaab36..5aea97f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Float.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Float.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Int.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Int.java index 6c2e760..31db411 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Int.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Int.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Matrix.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Matrix.java index e8281bd..e83cea5 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Matrix.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Matrix.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; import static org.lwjgl.opengl.GL20.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatLayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatLayer.java index 83f9d6f..7bf8161 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatLayer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatLayer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.flat; import ru.windcorp.progressia.client.graphics.Layer; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatRenderHelper.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatRenderHelper.java index 5696ac2..789a378 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatRenderHelper.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatRenderHelper.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.flat; import java.nio.FloatBuffer; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/DefaultFlatRenderHelper.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/DefaultFlatRenderHelper.java index 4ec676a..5550c24 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/DefaultFlatRenderHelper.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/DefaultFlatRenderHelper.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.flat; import java.nio.FloatBuffer; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatGraphics.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatGraphics.java index 2b615ec..e7723e6 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatGraphics.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatGraphics.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.flat; public class FlatGraphics { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderHelper.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderHelper.java index 704c579..1cdaf14 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderHelper.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderHelper.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.flat; import java.nio.FloatBuffer; @@ -37,9 +37,8 @@ public abstract class FlatRenderHelper extends ShapeRenderHelper { float width = GraphicsInterface.getFrameWidth(); float height = GraphicsInterface.getFrameHeight(); - return finalTransform.identity().translate(-1, -1, 0) - .scale(2 / width, 2 / height, 1 / MAX_DEPTH) - .mul(getTransform()); + return finalTransform.identity().translate(-1, -1, 0).scale(2 / width, 2 / height, 1 / MAX_DEPTH) + .mul(getTransform()); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderProgram.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderProgram.java index 774e6f3..aecc404 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderProgram.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderProgram.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.flat; import java.nio.FloatBuffer; @@ -33,10 +33,8 @@ public class FlatRenderProgram extends ShapeRenderProgram { private static FlatRenderProgram def = null; public static void init() { - def = new FlatRenderProgram( - new String[] { "FlatDefault.vertex.glsl" }, - new String[] { "FlatDefault.fragment.glsl" } - ); + def = new FlatRenderProgram(new String[] { "FlatDefault.vertex.glsl" }, + new String[] { "FlatDefault.fragment.glsl" }); } public static FlatRenderProgram getDefault() { @@ -48,20 +46,13 @@ public class FlatRenderProgram extends ShapeRenderProgram { private static final String FLAT_VERTEX_SHADER_RESOURCE = "Flat.vertex.glsl"; private static final String FLAT_FRAGMENT_SHADER_RESOURCE = "Flat.fragment.glsl"; - private static final String MASK_COUNT_UNIFORM_NAME = "maskCount", - MASKS_UNIFORM_NAME = "masks"; + private static final String MASK_COUNT_UNIFORM_NAME = "maskCount", MASKS_UNIFORM_NAME = "masks"; private final Uniform1Int maskCountUniform; private final Uniform2Float masksUniform; - public FlatRenderProgram( - String[] vertexShaderResources, - String[] fragmentShaderResources - ) { - super( - attachVertexShader(vertexShaderResources), - attachFragmentShader(fragmentShaderResources) - ); + public FlatRenderProgram(String[] vertexShaderResources, String[] fragmentShaderResources) { + super(attachVertexShader(vertexShaderResources), attachFragmentShader(fragmentShaderResources)); this.maskCountUniform = getUniform(MASK_COUNT_UNIFORM_NAME).as1Int(); this.masksUniform = getUniform(MASKS_UNIFORM_NAME).as2Float(); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/Mask.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/Mask.java index e13400a..2114c24 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/Mask.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/Mask.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.flat; public class Mask { @@ -88,8 +88,7 @@ public class Mask { @Override public String toString() { - return "(" + getStartX() + "; " + getStartY() + - ") -> (" + getEndX() + "; " + getEndY() + ")"; + return "(" + getStartX() + "; " + getStartY() + ") -> (" + getEndX() + "; " + getEndY() + ")"; } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/MaskStack.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/MaskStack.java index f114058..5f0e23c 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/MaskStack.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/MaskStack.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.flat; import java.nio.FloatBuffer; @@ -24,9 +24,8 @@ import org.lwjgl.BufferUtils; public class MaskStack { - private final FloatBuffer buffer = BufferUtils.createFloatBuffer( - FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS - ); + private final FloatBuffer buffer = BufferUtils + .createFloatBuffer(FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS); public void pushMask(TransformedMask mask) { mask.writeToBuffer(buffer); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java index 658b02d..70f5471 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java @@ -29,8 +29,8 @@ import glm.vec._3.Vec3; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.ShapePart; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.texture.Texture; @@ -84,7 +84,7 @@ public class RenderTarget { private final Deque maskStack = new LinkedList<>(); private final Deque transformStack = new LinkedList<>(); - private final List currentClipFaces = new ArrayList<>(); + private final List currentClipFaces = new ArrayList<>(); private int depth = 0; @@ -94,8 +94,8 @@ public class RenderTarget { protected void assembleCurrentClipFromFaces() { if (!currentClipFaces.isEmpty()) { - Face[] faces = currentClipFaces.toArray( - new Face[currentClipFaces.size()] + ShapePart[] faces = currentClipFaces.toArray( + new ShapePart[currentClipFaces.size()] ); currentClipFaces.clear(); @@ -195,7 +195,7 @@ public class RenderTarget { assembled.add(new Clip(maskStack, transform, renderable)); } - protected void addFaceToCurrentClip(Face face) { + protected void addFaceToCurrentClip(ShapePart face) { currentClipFaces.add(face); } @@ -267,7 +267,7 @@ public class RenderTarget { fill(Colors.toVector(color)); } - public Face createRectagleFace( + public ShapePart createRectagleFace( int x, int y, int width, @@ -277,7 +277,7 @@ public class RenderTarget { ) { float depth = this.depth--; - return Faces.createRectangle( + return ShapeParts.createRectangle( FlatRenderProgram.getDefault(), texture, color, @@ -288,7 +288,7 @@ public class RenderTarget { ); } - public Face createRectagleFace( + public ShapePart createRectagleFace( int x, int y, int width, diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/TransformedMask.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/TransformedMask.java index 5328cc8..0f17a52 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/TransformedMask.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/TransformedMask.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.flat; import java.nio.FloatBuffer; @@ -42,14 +42,8 @@ public class TransformedMask { private Vec4 endXstartY = null; private Vec4 endXendY = null; - public TransformedMask( - Vec2 origin, - Vec2 width, - Vec2 height, - Vec2 counterOrigin, - Vec2 counterWidth, - Vec2 counterHeight - ) { + public TransformedMask(Vec2 origin, Vec2 width, Vec2 height, Vec2 counterOrigin, Vec2 counterWidth, + Vec2 counterHeight) { set(origin, width, height, counterOrigin, counterWidth, counterHeight); } @@ -61,14 +55,8 @@ public class TransformedMask { // Do nothing } - public TransformedMask set( - Vec2 origin, - Vec2 width, - Vec2 height, - Vec2 counterOrigin, - Vec2 counterWidth, - Vec2 counterHeight - ) { + public TransformedMask set(Vec2 origin, Vec2 width, Vec2 height, Vec2 counterOrigin, Vec2 counterWidth, + Vec2 counterHeight) { this.origin.set(origin.x, origin.y); this.width.set(width.x, width.y); this.height.set(height.x, height.y); @@ -112,35 +100,17 @@ public class TransformedMask { } private void setFields() { - origin.set( - startXstartY.x, - startXstartY.y - ); + origin.set(startXstartY.x, startXstartY.y); - width.set( - endXstartY.x - startXstartY.x, - endXstartY.y - startXstartY.y - ); + width.set(endXstartY.x - startXstartY.x, endXstartY.y - startXstartY.y); - height.set( - startXendY.x - startXstartY.x, - startXendY.y - startXstartY.y - ); + height.set(startXendY.x - startXstartY.x, startXendY.y - startXstartY.y); - counterOrigin.set( - endXendY.x, - endXendY.y - ); + counterOrigin.set(endXendY.x, endXendY.y); - counterWidth.set( - startXendY.x - endXendY.x, - startXendY.y - endXendY.y - ); + counterWidth.set(startXendY.x - endXendY.x, startXendY.y - endXendY.y); - counterHeight.set( - endXstartY.x - endXendY.x, - endXstartY.y - endXendY.y - ); + counterHeight.set(endXstartY.x - endXendY.x, endXstartY.y - endXendY.y); } public void writeToBuffer(FloatBuffer output) { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java index 591ff83..c7524a4 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.font; import java.util.function.Supplier; @@ -68,17 +68,11 @@ public class Font { return color; } - public Renderable assemble( - CharSequence chars, - float maxWidth - ) { + public Renderable assemble(CharSequence chars, float maxWidth) { return typeface.assembleStatic(chars, style, align, maxWidth, color); } - public Renderable assembleDynamic( - Supplier supplier, - float maxWidth - ) { + public Renderable assembleDynamic(Supplier supplier, float maxWidth) { return typeface.assembleDynamic(supplier, style, align, maxWidth, color); } @@ -102,7 +96,8 @@ public class Font { * Creates a new {@link Font} with the specified {@code style} exactly. This * object's style is ignored. * - * @param style the new style + * @param style + * the new style * @return the new font */ public Font withStyle(int style) { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifont.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifont.java index f28975d..6b687b2 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifont.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifont.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.font; import gnu.trove.map.TCharObjectMap; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifontLoader.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifontLoader.java index 9ead1db..3725b91 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifontLoader.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifontLoader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.font; import java.io.BufferedReader; @@ -73,7 +73,7 @@ public class GNUUnifontLoader { public static GNUUnifont load(Resource resource) { try (BufferedReader reader = createReader(resource)) { return createStream(reader).map(GNUUnifontLoader::parse).map(GNUUnifontLoader::addToAtlas) - .collect(Collectors.collectingAndThen(createMapper(), GNUUnifont::new)); + .collect(Collectors.collectingAndThen(createMapper(), GNUUnifont::new)); } catch (IOException | UncheckedIOException e) { throw CrashReports.report(e, "Could not load GNUUnifont"); } @@ -81,8 +81,7 @@ public class GNUUnifontLoader { private static BufferedReader createReader(Resource resource) throws IOException { return new BufferedReader( - new InputStreamReader(new GZIPInputStream(resource.getInputStream()), StandardCharsets.UTF_8) - ); + new InputStreamReader(new GZIPInputStream(resource.getInputStream()), StandardCharsets.UTF_8)); } private static Stream createStream(BufferedReader reader) { @@ -97,13 +96,8 @@ public class GNUUnifontLoader { char c = getChar(declar); - TextureDataEditor editor = new TextureDataEditor( - width, - GNUUnifont.HEIGHT, - width, - GNUUnifont.HEIGHT, - TEXTURE_SETTINGS - ); + TextureDataEditor editor = new TextureDataEditor(width, GNUUnifont.HEIGHT, width, GNUUnifont.HEIGHT, + TEXTURE_SETTINGS); for (int y = 0; y < GNUUnifont.HEIGHT; ++y) { for (int x = 0; x < width; ++x) { @@ -165,8 +159,7 @@ public class GNUUnifontLoader { if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))) { throw new IOException( - "Illegal char in declar \"" + declar + "\" at index " + i + "; expected 0-9A-F" - ); + "Illegal char in declar \"" + declar + "\" at index " + i + "; expected 0-9A-F"); } } } @@ -190,18 +183,16 @@ public class GNUUnifontLoader { } private static Collector> createMapper() { - return Collector.of( - TCharObjectHashMap::new, + return Collector.of(TCharObjectHashMap::new, - (map, glyph) -> map.put(glyph.c, glyph.texture), + (map, glyph) -> map.put(glyph.c, glyph.texture), - (a, b) -> { - a.putAll(b); - return a; - }, + (a, b) -> { + a.putAll(b); + return a; + }, - Characteristics.UNORDERED - ); + Characteristics.UNORDERED); } private GNUUnifontLoader() { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java index 7920799..d1db43a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java @@ -33,8 +33,8 @@ import gnu.trove.stack.TIntStack; import gnu.trove.stack.array.TIntArrayStack; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.ShapePart; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; @@ -144,7 +144,7 @@ public abstract class SpriteTypeface extends Typeface { return new Shape( Usage.STATIC, getProgram(), - Faces.createRectangle( + ShapeParts.createRectangle( getProgram(), getTexture(c), Colors.WHITE, @@ -167,7 +167,7 @@ public abstract class SpriteTypeface extends Typeface { private final Renderable unitLine = new Shape( Usage.STATIC, getProgram(), - Faces.createRectangle( + ShapeParts.createRectangle( getProgram(), null, Vectors.UNIT_4, @@ -257,7 +257,7 @@ public abstract class SpriteTypeface extends Typeface { private class SDWorkspace extends SpriteTypeface.Workspace { - private final Collection faces = new ArrayList<>(); + private final Collection faces = new ArrayList<>(); private final Vec3 origin = new Vec3(); private final Vec3 width = new Vec3(); @@ -298,7 +298,7 @@ public abstract class SpriteTypeface extends Typeface { workspace.height.sub(workspace.origin); workspace.faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( getProgram(), texture, color, @@ -314,7 +314,7 @@ public abstract class SpriteTypeface extends Typeface { return new Shape( Usage.STATIC, getProgram(), - workspace.faces.toArray(new Face[workspace.faces.size()]) + workspace.faces.toArray(new ShapePart[workspace.faces.size()]) ); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/Typeface.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/Typeface.java index 3be5ebb..5cf83db 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/Typeface.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/Typeface.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.font; import java.util.function.Supplier; @@ -29,12 +29,8 @@ import ru.windcorp.progressia.common.util.Vectors; public abstract class Typeface extends Named { public static class Style { - public static final int BOLD = 1 << 0, - ITALIC = 1 << 1, - UNDERLINED = 1 << 2, - STRIKETHRU = 1 << 3, - SHADOW = 1 << 4, - OUTLINED = 1 << 5; + public static final int BOLD = 1 << 0, ITALIC = 1 << 1, UNDERLINED = 1 << 2, STRIKETHRU = 1 << 3, + SHADOW = 1 << 4, OUTLINED = 1 << 5; public static final int PLAIN = 0; @@ -71,40 +67,19 @@ public abstract class Typeface extends Named { super(name); } - public abstract Renderable assembleStatic( - CharSequence chars, - int style, - float align, - float maxWidth, - Vec4 color - ); + public abstract Renderable assembleStatic(CharSequence chars, int style, float align, float maxWidth, Vec4 color); - public abstract Renderable assembleDynamic( - Supplier supplier, - int style, - float align, - float maxWidth, - Vec4 color - ); + public abstract Renderable assembleDynamic(Supplier supplier, int style, float align, float maxWidth, + Vec4 color); - public int getWidth( - CharSequence chars, - int style, - float align, - float maxWidth - ) { + public int getWidth(CharSequence chars, int style, float align, float maxWidth) { Vec2i v = Vectors.grab2i(); v = getSize(chars, style, align, maxWidth, v); Vectors.release(v); return v.x; } - public int getHeight( - CharSequence chars, - int style, - float align, - float maxWidth - ) { + public int getHeight(CharSequence chars, int style, float align, float maxWidth) { Vec2i v = Vectors.grab2i(); v = getSize(chars, style, align, maxWidth, v); Vectors.release(v); @@ -113,13 +88,7 @@ public abstract class Typeface extends Named { public abstract int getLineHeight(); - public abstract Vec2i getSize( - CharSequence chars, - int style, - float align, - float maxWidth, - Vec2i result - ); + public abstract Vec2i getSize(CharSequence chars, int style, float align, float maxWidth, Vec2i result); public abstract boolean supports(char c); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/Typefaces.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/Typefaces.java index ed9c7c4..813087d 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/Typefaces.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/Typefaces.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.font; public class Typefaces { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java index bb6f24d..f9db88f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui; import java.util.Collections; @@ -542,11 +542,8 @@ public class Component extends Named { eventBus.post(event); } - public void addListener( - Class type, - boolean handlesConsumed, - InputListener listener - ) { + public void addListener(Class type, boolean handlesConsumed, + InputListener listener) { if (inputBus == null) { inputBus = new InputBus(); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java index bddad7b..ff62027 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui; import glm.mat._4.Mat4; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/GUILayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/GUILayer.java index 2e0981c..9a4c648 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/GUILayer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/GUILayer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui; import ru.windcorp.progressia.client.graphics.flat.AssembledFlatLayer; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Group.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Group.java old mode 100755 new mode 100644 diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Layout.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Layout.java index 8d5d84f..4d08ed4 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Layout.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Layout.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui; import glm.vec._2.i.Vec2i; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java old mode 100644 new mode 100755 diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildAddedEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildAddedEvent.java index f1611fe..9bbf93a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildAddedEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildAddedEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.event; import ru.windcorp.progressia.client.graphics.gui.Component; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildEvent.java index a27cf79..0d63e38 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.event; import ru.windcorp.progressia.client.graphics.gui.Component; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildRemovedEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildRemovedEvent.java index 897d787..ec2e46c 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildRemovedEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildRemovedEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.event; import ru.windcorp.progressia.client.graphics.gui.Component; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ComponentEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ComponentEvent.java index b1d1175..dbf6e1c 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ComponentEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ComponentEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.event; import ru.windcorp.progressia.client.graphics.gui.Component; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/FocusEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/FocusEvent.java index ff859f3..fe476c2 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/FocusEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/FocusEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.event; import ru.windcorp.progressia.client.graphics.gui.Component; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HierarchyEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HierarchyEvent.java index d3a4984..5195c7e 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HierarchyEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HierarchyEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.event; import ru.windcorp.progressia.client.graphics.gui.Component; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HoverEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HoverEvent.java index b1d63ad..1e788f9 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HoverEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HoverEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.event; import ru.windcorp.progressia.client.graphics.gui.Component; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ParentChangedEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ParentChangedEvent.java index a7d9d40..ca5556a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ParentChangedEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ParentChangedEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.event; import ru.windcorp.progressia.client.graphics.gui.Component; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutAlign.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutAlign.java index d521914..422e108 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutAlign.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutAlign.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.layout; import static java.lang.Math.max; @@ -56,13 +56,8 @@ public class LayoutAlign implements Layout { size.x = min(size.x, cWidth); size.y = min(size.y, cHeight); - child.setBounds( - c.getX() + - (int) ((cWidth - size.x) * alignX) + margin, - c.getY() + - (int) ((cHeight - size.y) * alignY) + margin, - size - ); + child.setBounds(c.getX() + (int) ((cWidth - size.x) * alignX) + margin, + c.getY() + (int) ((cHeight - size.y) * alignY) + margin, size); }); } @@ -71,12 +66,10 @@ public class LayoutAlign implements Layout { public Vec2i calculatePreferredSize(Component c) { Vec2i result = new Vec2i(0, 0); - c.getChildren().stream() - .map(child -> child.getPreferredSize()) - .forEach(size -> { - result.x = max(size.x, result.x); - result.y = max(size.y, result.y); - }); + c.getChildren().stream().map(child -> child.getPreferredSize()).forEach(size -> { + result.x = max(size.x, result.x); + result.y = max(size.y, result.y); + }); result.x += 2 * margin; result.y += 2 * margin; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderHorizontal.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderHorizontal.java index 3e271de..05b9723 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderHorizontal.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderHorizontal.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.layout; import static java.lang.Math.max; @@ -26,9 +26,7 @@ import ru.windcorp.progressia.client.graphics.gui.Layout; public class LayoutBorderHorizontal implements Layout { - public static final String CENTER = "Center", - LEFT = "Left", - RIGHT = "Right"; + public static final String CENTER = "Center", LEFT = "Left", RIGHT = "Right"; private final int margin; @@ -51,32 +49,17 @@ public class LayoutBorderHorizontal implements Layout { if (child.getLayoutHint() == LEFT) { childSize = child.getPreferredSize(); left = childSize.x + margin; - child.setBounds( - c.getX(), - c.getY(), - childSize.x, - c.getHeight() - ); + child.setBounds(c.getX(), c.getY(), childSize.x, c.getHeight()); } else if (child.getLayoutHint() == RIGHT) { childSize = child.getPreferredSize(); right = childSize.x + margin; - child.setBounds( - c.getX() + c.getWidth() - childSize.x, - c.getY(), - childSize.x, - c.getHeight() - ); + child.setBounds(c.getX() + c.getWidth() - childSize.x, c.getY(), childSize.x, c.getHeight()); } } for (Component child : c.getChildren()) { if (child.getLayoutHint() == CENTER) { - child.setBounds( - c.getX() + left, - c.getY(), - c.getWidth() - left - right, - c.getHeight() - ); + child.setBounds(c.getX() + left, c.getY(), c.getWidth() - left - right, c.getHeight()); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderVertical.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderVertical.java index 0efcaa4..1d94db4 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderVertical.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderVertical.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.layout; import static java.lang.Math.max; @@ -26,9 +26,7 @@ import ru.windcorp.progressia.client.graphics.gui.Layout; public class LayoutBorderVertical implements Layout { - public static final String CENTER = "Center", - UP = "Up", - DOWN = "Down"; + public static final String CENTER = "Center", UP = "Up", DOWN = "Down"; private final int margin; @@ -51,32 +49,17 @@ public class LayoutBorderVertical implements Layout { if (child.getLayoutHint() == UP) { childSize = child.getPreferredSize(); top = childSize.y + margin; - child.setBounds( - c.getX(), - c.getY(), - c.getWidth(), - childSize.y - ); + child.setBounds(c.getX(), c.getY(), c.getWidth(), childSize.y); } else if (child.getLayoutHint() == DOWN) { childSize = child.getPreferredSize(); bottom = childSize.y + margin; - child.setBounds( - c.getX(), - c.getY() + c.getHeight() - childSize.y, - c.getWidth(), - childSize.y - ); + child.setBounds(c.getX(), c.getY() + c.getHeight() - childSize.y, c.getWidth(), childSize.y); } } for (Component child : c.getChildren()) { if (child.getLayoutHint() == CENTER) { - child.setBounds( - c.getX(), - c.getY() + top, - c.getWidth(), - c.getHeight() - top - bottom - ); + child.setBounds(c.getX(), c.getY() + top, c.getWidth(), c.getHeight() - top - bottom); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutHorizontal.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutHorizontal.java index 85c37fa..5ce33b4 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutHorizontal.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutHorizontal.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.layout; import static java.lang.Math.max; @@ -43,8 +43,7 @@ public class LayoutHorizontal implements Layout { @Override public void layout(Component c) { - int x = c.getX() + margin, - y = c.getY() + margin; + int x = c.getX() + margin, y = c.getY() + margin; int width; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutVertical.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutVertical.java index 6e48d69..d03e124 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutVertical.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutVertical.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.gui.layout; import static java.lang.Math.max; @@ -43,8 +43,7 @@ public class LayoutVertical implements Layout { @Override public void layout(Component c) { - int x = c.getX() + margin, - y = c.getY() + c.getHeight(); + int x = c.getX() + margin, y = c.getY() + c.getHeight(); synchronized (c.getChildren()) { for (Component child : c.getChildren()) { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorEvent.java index 43dd965..8bc480b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input; import glm.vec._2.d.Vec2d; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorMoveEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorMoveEvent.java index c87fc62..ccb107f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorMoveEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorMoveEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input; import glm.vec._2.Vec2; @@ -87,22 +87,14 @@ public class CursorMoveEvent extends CursorEvent { @Override public CursorMoveEvent snapshot() { - return new StaticMouseMoveEvent( - getPreviousPosition(), - getNewPosition(), - getTime() - ); + return new StaticMouseMoveEvent(getPreviousPosition(), getNewPosition(), getTime()); } private class StaticMouseMoveEvent extends CursorMoveEvent { private final Vec2d previousPosition = new Vec2d(); - public StaticMouseMoveEvent( - Vec2d previousPosition, - Vec2d newPosition, - double time - ) { + public StaticMouseMoveEvent(Vec2d previousPosition, Vec2d newPosition, double time) { super(newPosition, time); this.previousPosition.set(previousPosition.x, previousPosition.y); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/FrameResizeEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/FrameResizeEvent.java index 5589158..cf1a296 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/FrameResizeEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/FrameResizeEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input; import glm.vec._2.i.Vec2i; @@ -67,11 +67,7 @@ public class FrameResizeEvent extends InputEvent { private final Vec2i previousSize; - public StaticFrameResizeEvent( - Vec2i newSize, - Vec2i previousSize, - double time - ) { + public StaticFrameResizeEvent(Vec2i newSize, Vec2i previousSize, double time) { super(newSize, time); this.previousSize = previousSize; } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/InputEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/InputEvent.java index b0c2483..dc8a187 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/InputEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/InputEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input; public abstract class InputEvent { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyEvent.java index 291b89e..c36e059 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input; import org.lwjgl.glfw.GLFW; @@ -27,13 +27,7 @@ public class KeyEvent extends InputEvent { protected int action; protected int mods; - protected KeyEvent( - int key, - int scancode, - int action, - int mods, - double time - ) { + protected KeyEvent(int key, int scancode, int action, int mods, double time) { super(time); this.key = key; this.scancode = scancode; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java index 6fedcd6..6073a7b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input; import java.util.function.Predicate; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/Keys.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/Keys.java index 3904f59..e0d6980 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/Keys.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/Keys.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input; import java.lang.reflect.Field; @@ -46,17 +46,12 @@ public class Keys { private static final String MOUSE_BUTTON_PREFIX = "GLFW_MOUSE_BUTTON_"; private static final Set IGNORE_FIELDS = new HashSet<>( - Arrays.asList( - "GLFW_KEY_UNKNOWN", - "GLFW_KEY_LAST", - "GLFW_MOUSE_BUTTON_LAST", - "GLFW_MOUSE_BUTTON_1", // Alias - // for - // LEFT - "GLFW_MOUSE_BUTTON_2", // Alias for RIGHT - "GLFW_MOUSE_BUTTON_3" // Alias for MIDDLE - ) - ); + Arrays.asList("GLFW_KEY_UNKNOWN", "GLFW_KEY_LAST", "GLFW_MOUSE_BUTTON_LAST", "GLFW_MOUSE_BUTTON_1", // Alias + // for + // LEFT + "GLFW_MOUSE_BUTTON_2", // Alias for RIGHT + "GLFW_MOUSE_BUTTON_3" // Alias for MIDDLE + )); static { initializeDictionary(); @@ -100,14 +95,8 @@ public class Keys { } if (CODES_TO_NAMES.containsKey(value)) { - throw CrashReports.report( - null, - "Duplicate keys: %s and %s both map to %d(0x%s)", - CODES_TO_NAMES.get(value), - name, - value, - Integer.toHexString(value) - ); + throw CrashReports.report(null, "Duplicate keys: %s and %s both map to %d(0x%s)", CODES_TO_NAMES.get(value), + name, value, Integer.toHexString(value)); } CODES_TO_NAMES.put(value, name); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelEvent.java index 24938c3..80c5282 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input; public abstract class WheelEvent extends InputEvent { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelScrollEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelScrollEvent.java index 968ff64..0ba2d2b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelScrollEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelScrollEvent.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input; import glm.vec._2.d.Vec2d; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/Input.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/Input.java index 1aad6bb..46da738 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/Input.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/Input.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input.bus; import ru.windcorp.progressia.client.graphics.input.InputEvent; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputBus.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputBus.java index a22a243..665831f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputBus.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputBus.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input.bus; import java.util.ArrayList; @@ -31,28 +31,21 @@ public class InputBus { private final boolean handleConsumed; private final InputListener listener; - public WrappedListener( - Class type, - boolean handleConsumed, - InputListener listener - ) { + public WrappedListener(Class type, boolean handleConsumed, InputListener listener) { this.type = type; this.handleConsumed = handleConsumed; this.listener = listener; } private boolean handles(Input input) { - return (!input.isConsumed() || handleConsumed) && - type.isInstance(input.getEvent()); + return (!input.isConsumed() || handleConsumed) && type.isInstance(input.getEvent()); } @SuppressWarnings("unchecked") public void handle(Input input) { if (handles(input)) { boolean consumed = ((InputListener) listener) - .handle( - (InputEvent) type.cast(input.getEvent()) - ); + .handle((InputEvent) type.cast(input.getEvent())); input.setConsumed(consumed); } @@ -66,18 +59,12 @@ public class InputBus { listeners.forEach(l -> l.handle(input)); } - public void register( - Class type, - boolean handlesConsumed, - InputListener listener - ) { + public void register(Class type, boolean handlesConsumed, + InputListener listener) { listeners.add(new WrappedListener(type, handlesConsumed, listener)); } - public void register( - Class type, - InputListener listener - ) { + public void register(Class type, InputListener listener) { register(type, false, listener); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputListener.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputListener.java index 0d68b5e..f6e3811 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputListener.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputListener.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.input.bus; import ru.windcorp.progressia.client.graphics.input.InputEvent; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java index 3b929c0..7d94fb2 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java @@ -18,23 +18,23 @@ package ru.windcorp.progressia.client.graphics.model; -import static ru.windcorp.progressia.common.world.block.BlockFace.*; +import static ru.windcorp.progressia.common.world.rels.AbsFace.*; import com.google.common.collect.ImmutableMap; import glm.vec._3.Vec3; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; class BlockFaceVectors { private static BlockFaceVectors createInner(BlockFaceVectors outer) { - ImmutableMap.Builder originBuilder = ImmutableMap.builder(); + ImmutableMap.Builder originBuilder = ImmutableMap.builder(); - ImmutableMap.Builder widthBuilder = ImmutableMap.builder(); + ImmutableMap.Builder widthBuilder = ImmutableMap.builder(); - ImmutableMap.Builder heightBuilder = ImmutableMap.builder(); + ImmutableMap.Builder heightBuilder = ImmutableMap.builder(); - for (BlockFace face : getFaces()) { + for (AbsFace face : getFaces()) { Vec3 width = outer.getWidth(face); Vec3 height = outer.getHeight(face); @@ -59,36 +59,36 @@ class BlockFaceVectors { static { OUTER = new BlockFaceVectors( - ImmutableMap.builder() + ImmutableMap.builder() - .put(TOP, new Vec3(-0.5f, +0.5f, +0.5f)) - .put(BOTTOM, new Vec3(-0.5f, -0.5f, -0.5f)) - .put(NORTH, new Vec3(+0.5f, -0.5f, -0.5f)) - .put(SOUTH, new Vec3(-0.5f, +0.5f, -0.5f)) - .put(WEST, new Vec3(+0.5f, +0.5f, -0.5f)) - .put(EAST, new Vec3(-0.5f, -0.5f, -0.5f)) + .put(POS_Z, new Vec3(-0.5f, +0.5f, +0.5f)) + .put(NEG_Z, new Vec3(-0.5f, -0.5f, -0.5f)) + .put(POS_X, new Vec3(+0.5f, -0.5f, -0.5f)) + .put(NEG_X, new Vec3(-0.5f, +0.5f, -0.5f)) + .put(POS_Y, new Vec3(+0.5f, +0.5f, -0.5f)) + .put(NEG_Y, new Vec3(-0.5f, -0.5f, -0.5f)) .build(), - ImmutableMap.builder() + ImmutableMap.builder() - .put(TOP, new Vec3(0, -1, 0)) - .put(BOTTOM, new Vec3(0, +1, 0)) - .put(NORTH, new Vec3(0, +1, 0)) - .put(SOUTH, new Vec3(0, -1, 0)) - .put(WEST, new Vec3(-1, 0, 0)) - .put(EAST, new Vec3(+1, 0, 0)) + .put(POS_Z, new Vec3(0, -1, 0)) + .put(NEG_Z, new Vec3(0, +1, 0)) + .put(POS_X, new Vec3(0, +1, 0)) + .put(NEG_X, new Vec3(0, -1, 0)) + .put(POS_Y, new Vec3(-1, 0, 0)) + .put(NEG_Y, new Vec3(+1, 0, 0)) .build(), - ImmutableMap.builder() + ImmutableMap.builder() - .put(TOP, new Vec3(+1, 0, 0)) - .put(BOTTOM, new Vec3(+1, 0, 0)) - .put(NORTH, new Vec3(0, 0, +1)) - .put(SOUTH, new Vec3(0, 0, +1)) - .put(WEST, new Vec3(0, 0, +1)) - .put(EAST, new Vec3(0, 0, +1)) + .put(POS_Z, new Vec3(+1, 0, 0)) + .put(NEG_Z, new Vec3(+1, 0, 0)) + .put(POS_X, new Vec3(0, 0, +1)) + .put(NEG_X, new Vec3(0, 0, +1)) + .put(POS_Y, new Vec3(0, 0, +1)) + .put(NEG_Y, new Vec3(0, 0, +1)) .build() ); @@ -100,29 +100,29 @@ class BlockFaceVectors { return inner ? INNER : OUTER; } - private final ImmutableMap origins; - private final ImmutableMap widths; - private final ImmutableMap heights; + private final ImmutableMap origins; + private final ImmutableMap widths; + private final ImmutableMap heights; public BlockFaceVectors( - ImmutableMap origins, - ImmutableMap widths, - ImmutableMap heights + ImmutableMap origins, + ImmutableMap widths, + ImmutableMap heights ) { this.origins = origins; this.widths = widths; this.heights = heights; } - public Vec3 getOrigin(BlockFace face) { + public Vec3 getOrigin(AbsFace face) { return origins.get(face); } - public Vec3 getWidth(BlockFace face) { + public Vec3 getWidth(AbsFace face) { return widths.get(face); } - public Vec3 getHeight(BlockFace face) { + public Vec3 getHeight(AbsFace face) { return heights.get(face); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/DynamicModel.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/DynamicModel.java index 9460bd7..80f880a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/DynamicModel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/DynamicModel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.model; import java.util.ArrayList; @@ -33,22 +33,14 @@ public abstract class DynamicModel extends Model { private final Mat4[] transforms; private final boolean[] dynamics; - public DynamicModel( - Renderable[] parts, - Mat4[] transforms, - boolean[] dynamic - ) { + public DynamicModel(Renderable[] parts, Mat4[] transforms, boolean[] dynamic) { super(parts); this.transforms = transforms; this.dynamics = dynamic; } public DynamicModel(Builder builder) { - this( - builder.getParts(), - builder.getTransforms(), - builder.getDynamics() - ); + this(builder.getParts(), builder.getTransforms(), builder.getDynamics()); } @Override @@ -78,11 +70,7 @@ public abstract class DynamicModel extends Model { protected Builder() { } - private Builder addPart( - Renderable part, - Mat4 transform, - boolean isDynamic - ) { + private Builder addPart(Renderable part, Mat4 transform, boolean isDynamic) { parts.add(Objects.requireNonNull(part, "part")); transforms.add(Objects.requireNonNull(transform, "transform")); dynamics.add(isDynamic); @@ -90,22 +78,15 @@ public abstract class DynamicModel extends Model { return this; } - public Builder addStaticPart( - Renderable part, - Mat4 transform - ) { + public Builder addStaticPart(Renderable part, Mat4 transform) { return addPart(part, new Mat4(transform), false); } - public Builder addDynamicPart( - Renderable part - ) { + public Builder addDynamicPart(Renderable part) { return addPart(part, new Mat4(), true); } - public Builder addStaticPart( - Renderable part - ) { + public Builder addStaticPart(Renderable part) { return addStaticPart(part, IDENTITY); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/EmptyModel.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/EmptyModel.java index f9cff67..f3e40a0 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/EmptyModel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/EmptyModel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.model; import glm.mat._4.Mat4; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java index 0ae31bf..b38df91 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.model; import java.util.ArrayList; @@ -37,23 +37,13 @@ public class LambdaModel extends DynamicModel { private final TransformGetter[] getters; - public LambdaModel( - Renderable[] parts, - Mat4[] transforms, - boolean[] dynamic, - TransformGetter[] getters - ) { + public LambdaModel(Renderable[] parts, Mat4[] transforms, boolean[] dynamic, TransformGetter[] getters) { super(parts, transforms, dynamic); this.getters = getters; } public LambdaModel(Builder builder) { - this( - builder.getParts(), - builder.getTransforms(), - builder.getDynamics(), - builder.getGetters() - ); + this(builder.getParts(), builder.getTransforms(), builder.getDynamics(), builder.getGetters()); } @Override @@ -75,11 +65,7 @@ public class LambdaModel extends DynamicModel { protected Builder() { } - private Builder addPart( - Renderable part, - Mat4 transform, - TransformGetter getter - ) { + private Builder addPart(Renderable part, Mat4 transform, TransformGetter getter) { parts.add(Objects.requireNonNull(part, "part")); transforms.add(Objects.requireNonNull(transform, "transform")); dynamics.add(getter != null); @@ -88,23 +74,15 @@ public class LambdaModel extends DynamicModel { return this; } - public Builder addStaticPart( - Renderable part, - Mat4 transform - ) { + public Builder addStaticPart(Renderable part, Mat4 transform) { return addPart(part, new Mat4(transform), null); } - public Builder addDynamicPart( - Renderable part, - TransformGetter getter - ) { + public Builder addDynamicPart(Renderable part, TransformGetter getter) { return addPart(part, new Mat4(), getter); } - public Builder addStaticPart( - Renderable part - ) { + public Builder addStaticPart(Renderable part) { return addStaticPart(part, IDENTITY); } @@ -127,12 +105,8 @@ public class LambdaModel extends DynamicModel { } public static LambdaModel animate(Renderable model, TransformGetter transform) { - return new LambdaModel( - new Renderable[] { model }, - new Mat4[] { new Mat4() }, - new boolean[] { true }, - new TransformGetter[] { transform } - ); + return new LambdaModel(new Renderable[] { model }, new Mat4[] { new Mat4() }, new boolean[] { true }, + new TransformGetter[] { transform }); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Model.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Model.java index 47cd88b..5e59007 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Model.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Model.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.model; import glm.mat._4.Mat4; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Renderable.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Renderable.java index 6063685..b379b75 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Renderable.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Renderable.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.model; public interface Renderable { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java index 145b149..a70eede 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.model; import java.nio.ByteBuffer; @@ -30,10 +30,10 @@ import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; public class Shape implements Renderable { private final ShapeRenderProgram program; - private final Face[] faces; + private final ShapePart[] parts; private final Usage usage; - private FaceGroup[] groups; + private ShapePartGroup[] groups; private ByteBuffer vertices; private ShortBuffer indices; @@ -45,33 +45,33 @@ public class Shape implements Renderable { private VertexBufferObject verticesVbo; private VertexBufferObject indicesVbo; - public Shape(Usage usage, ShapeRenderProgram program, Face... faces) { + public Shape(Usage usage, ShapeRenderProgram program, ShapePart... parts) { this.program = program; - this.faces = faces; + this.parts = parts; this.usage = usage; - configureFaces(); + configureParts(); program.preprocess(this); assembleBuffers(); } - private void configureFaces() { - for (Face face : faces) { - face.setShape(this); + private void configureParts() { + for (ShapePart part : parts) { + part.setShape(this); } } private void assembleBuffers() { // TODO optimize: only update faces that requested it - sortFaces(); + sortParts(); resizeBuffers(); - for (Face face : faces) { - assembleVertices(face); - assembleIndices(face); - face.resetUpdateFlags(); + for (ShapePart part : parts) { + assembleVertices(part); + assembleIndices(part); + part.resetUpdateFlags(); } this.vertices.flip(); @@ -85,110 +85,110 @@ public class Shape implements Renderable { private void resizeBuffers() { int verticesRequired = 0, indicesRequired = 0; - for (Face face : faces) { - verticesRequired += face.getVertices().remaining(); - indicesRequired += face.getIndices().remaining(); + for (ShapePart part : parts) { + verticesRequired += part.getVertices().remaining(); + indicesRequired += part.getIndices().remaining(); } - if (this.vertices == null || vertices.capacity() < verticesRequired) { + if (vertices == null || vertices.capacity() < verticesRequired) { this.vertices = BufferUtils.createByteBuffer(verticesRequired); } else { - this.vertices.position(0).limit(verticesRequired); + vertices.position(0).limit(verticesRequired); } - if (this.indices == null || this.indices.capacity() < indicesRequired) { + if (indices == null || indices.capacity() < indicesRequired) { this.indices = BufferUtils.createShortBuffer(indicesRequired); } else { - this.indices.position(0).limit(indicesRequired); + indices.position(0).limit(indicesRequired); } } - private void assembleVertices(Face face) { - face.locationOfVertices = this.vertices.position(); + private void assembleVertices(ShapePart part) { + part.locationOfVertices = this.vertices.position(); - insertVertices(face); - linkVerticesWith(face); + insertVertices(part); + linkVerticesWith(part); } - private void insertVertices(Face face) { - ByteBuffer faceVertices = face.getVertices(); + private void insertVertices(ShapePart part) { + ByteBuffer partVertices = part.getVertices(); - faceVertices.mark(); - this.vertices.put(faceVertices); - faceVertices.reset(); + partVertices.mark(); + this.vertices.put(partVertices); + partVertices.reset(); } - private void linkVerticesWith(Face face) { + private void linkVerticesWith(ShapePart part) { int limit = vertices.limit(); int position = vertices.position(); - vertices.limit(position).position(face.getLocationOfVertices()); - face.vertices = vertices.slice(); + vertices.limit(position).position(part.getLocationOfVertices()); + part.vertices = vertices.slice(); vertices.position(position).limit(limit); } - private void assembleIndices(Face face) { - short vertexOffset = (short) (face.getLocationOfVertices() / program.getBytesPerVertex()); + private void assembleIndices(ShapePart part) { + short vertexOffset = (short) (part.getLocationOfVertices() / program.getBytesPerVertex()); - face.locationOfIndices = indices.position(); + part.locationOfIndices = indices.position(); - ShortBuffer faceIndices = face.getIndices(); + ShortBuffer partIndices = part.getIndices(); - if (faceIndices == null) { - for (int i = 0; i < face.getVertexCount(); ++i) { + if (partIndices == null) { + for (int i = 0; i < part.getVertexCount(); ++i) { this.indices.put((short) (vertexOffset + i)); } } else { - for (int i = faceIndices.position(); i < faceIndices.limit(); ++i) { - short faceIndex = faceIndices.get(i); - faceIndex += vertexOffset; - this.indices.put(faceIndex); + for (int i = partIndices.position(); i < partIndices.limit(); ++i) { + short partIndex = partIndices.get(i); + partIndex += vertexOffset; + this.indices.put(partIndex); } } } - private void sortFaces() { - Arrays.sort(faces); + private void sortParts() { + Arrays.sort(parts); } private void assembleGroups() { - int unique = countUniqueFaces(); - this.groups = new FaceGroup[unique]; + int unique = countUniqueParts(); + this.groups = new ShapePartGroup[unique]; - if (faces.length == 0) + if (parts.length == 0) return; - int previousHandle = faces[0].getSortingIndex(); + int previousHandle = parts[0].getSortingIndex(); int start = 0; int groupIndex = 0; - for (int i = 1; i < faces.length; ++i) { - if (previousHandle != faces[i].getSortingIndex()) { + for (int i = 1; i < parts.length; ++i) { + if (previousHandle != parts[i].getSortingIndex()) { - groups[groupIndex] = new FaceGroup(faces, start, i); + groups[groupIndex] = new ShapePartGroup(parts, start, i); start = i; groupIndex++; - previousHandle = faces[i].getSortingIndex(); + previousHandle = parts[i].getSortingIndex(); } } assert groupIndex == groups.length - 1; - groups[groupIndex] = new FaceGroup(faces, start, faces.length); + groups[groupIndex] = new ShapePartGroup(parts, start, parts.length); } - private int countUniqueFaces() { - if (faces.length == 0) + private int countUniqueParts() { + if (parts.length == 0) return 0; int result = 1; - int previousHandle = faces[0].getSortingIndex(); + int previousHandle = parts[0].getSortingIndex(); - for (int i = 1; i < faces.length; ++i) { - if (previousHandle != faces[i].getSortingIndex()) { + for (int i = 1; i < parts.length; ++i) { + if (previousHandle != parts[i].getSortingIndex()) { result++; - previousHandle = faces[i].getSortingIndex(); + previousHandle = parts[i].getSortingIndex(); } } @@ -238,11 +238,11 @@ public class Shape implements Renderable { return program; } - public Face[] getFaces() { - return faces; + public ShapePart[] getParts() { + return parts; } - public FaceGroup[] getGroups() { + public ShapePartGroup[] getGroups() { return groups; } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Face.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePart.java similarity index 95% rename from src/main/java/ru/windcorp/progressia/client/graphics/model/Face.java rename to src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePart.java index 79da464..aef0ad9 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Face.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePart.java @@ -24,7 +24,7 @@ import java.util.Objects; import ru.windcorp.progressia.client.graphics.texture.Texture; -public class Face implements Comparable { +public class ShapePart implements Comparable { private static final ShortBuffer GENERATE_SUCCESSIVE_LATER = null; @@ -40,7 +40,7 @@ public class Face implements Comparable { private ShortBuffer userIndices; private boolean userIndicesUpdated = true; - public Face( + public ShapePart( Texture texture, ByteBuffer vertices, ShortBuffer indices @@ -50,7 +50,7 @@ public class Face implements Comparable { setIndices(indices); } - public Face( + public ShapePart( Texture texture, ByteBuffer vertices ) { @@ -155,7 +155,7 @@ public class Face implements Comparable { return vertices; } - public Face setVertices(ByteBuffer vertices) { + public ShapePart setVertices(ByteBuffer vertices) { this.vertices = Objects.requireNonNull(vertices, "vertices"); markForVertexUpdate(); return this; @@ -202,7 +202,7 @@ public class Face implements Comparable { return userIndices.remaining(); } - public Face setIndices(ShortBuffer indices) { + public ShapePart setIndices(ShortBuffer indices) { if (indices == null) { indices = GENERATE_SUCCESSIVE_LATER; } @@ -245,7 +245,7 @@ public class Face implements Comparable { } @Override - public int compareTo(Face o) { + public int compareTo(ShapePart o) { return Integer.compare(getSortingIndex(), o.getSortingIndex()); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/FaceGroup.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePartGroup.java similarity index 86% rename from src/main/java/ru/windcorp/progressia/client/graphics/model/FaceGroup.java rename to src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePartGroup.java index ee91544..e5fcee4 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/FaceGroup.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePartGroup.java @@ -15,19 +15,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.model; import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive; -public class FaceGroup { +public class ShapePartGroup { private final TexturePrimitive texture; private final int indexCount; private final int byteOffsetOfIndices; - FaceGroup(Face[] faces, int start, int end) { + ShapePartGroup(ShapePart[] faces, int start, int end) { Texture t = faces[start].getTexture(); this.texture = t == null ? null : t.getSprite().getPrimitive(); @@ -36,11 +36,10 @@ public class FaceGroup { int indexCount = 0; for (int i = start; i < end; ++i) { - Face face = faces[i]; + ShapePart face = faces[i]; - assert this.texture == null - ? (face.getTexture() == null) - : (face.getTexture().getSprite().getPrimitive() == this.texture); + assert this.texture == null ? (face.getTexture() == null) + : (face.getTexture().getSprite().getPrimitive() == this.texture); indexCount += face.getIndexCount(); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeParts.java similarity index 90% rename from src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java rename to src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeParts.java index d1e9c07..50f744f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeParts.java @@ -25,14 +25,14 @@ import glm.vec._3.Vec3; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; -public class Faces { +public class ShapeParts { - private Faces() { + private ShapeParts() { } - public static Face createRectangle( + public static ShapePart createRectangle( ShapeRenderProgram program, Texture texture, Vec4 colorMultiplier, @@ -82,19 +82,19 @@ public class Faces { } ); - return new Face( + return new ShapePart( texture, builder.assemble(), buffer ); } - public static Face createBlockFace( + public static ShapePart createBlockFace( ShapeRenderProgram program, Texture texture, Vec4 colorMultiplier, Vec3 blockCenter, - BlockFace face, + AbsFace face, boolean inner ) { BlockFaceVectors vectors = BlockFaceVectors.get(inner); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderHelper.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderHelper.java index 67578f6..517c711 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderHelper.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderHelper.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.model; import glm.mat._4.Mat4; @@ -28,15 +28,10 @@ public class ShapeRenderHelper { protected static final int TRANSFORM_STACK_SIZE = 64; protected static final int COLOR_MULTIPLIER_STACK_SIZE = TRANSFORM_STACK_SIZE; - protected final StashingStack transformStack = new StashingStack<>( - TRANSFORM_STACK_SIZE, - Mat4::new - ); + protected final StashingStack transformStack = new StashingStack<>(TRANSFORM_STACK_SIZE, Mat4::new); - protected final StashingStack colorMultiplierStack = new StashingStack<>( - COLOR_MULTIPLIER_STACK_SIZE, - Vec4::new - ); + protected final StashingStack colorMultiplierStack = new StashingStack<>(COLOR_MULTIPLIER_STACK_SIZE, + Vec4::new); { transformStack.push().identity(); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java index e27bc77..ab4b12a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.model; import java.nio.ByteBuffer; @@ -43,19 +43,18 @@ import ru.windcorp.progressia.common.util.Vectors; public class ShapeRenderProgram extends Program { private static final int DEFAULT_BYTES_PER_VERTEX = 3 * Float.BYTES + // Position - 4 * Float.BYTES + // Color multiplier - 2 * Float.BYTES; // Texture coordinates + 4 * Float.BYTES + // Color multiplier + 2 * Float.BYTES; // Texture coordinates private static final String SHAPE_VERTEX_SHADER_RESOURCE = "Shape.vertex.glsl"; private static final String SHAPE_FRAGMENT_SHADER_RESOURCE = "Shape.fragment.glsl"; private static final String FINAL_TRANSFORM_UNIFORM_NAME = "finalTransform", - POSITIONS_ATTRIBUTE_NAME = "inputPositions", - UNIFORM_COLOR_MULTIPLER_ATTRIBUTE_NAME = "uniformColorMultiplier", - ATTRIBUTE_COLOR_MULTIPLER_ATTRIBUTE_NAME = "inputColorMultiplier", - TEXTURE_COORDS_ATTRIBUTE_NAME = "inputTextureCoords", - USE_TEXTURE_UNIFORM_NAME = "useTexture", - TEXTURE_SLOT_UNIFORM_NAME = "textureSlot"; + POSITIONS_ATTRIBUTE_NAME = "inputPositions", + UNIFORM_COLOR_MULTIPLER_ATTRIBUTE_NAME = "uniformColorMultiplier", + ATTRIBUTE_COLOR_MULTIPLER_ATTRIBUTE_NAME = "inputColorMultiplier", + TEXTURE_COORDS_ATTRIBUTE_NAME = "inputTextureCoords", USE_TEXTURE_UNIFORM_NAME = "useTexture", + TEXTURE_SLOT_UNIFORM_NAME = "textureSlot"; private final Uniform4Matrix finalTransformUniform; private final AttributeVertexArray positionsAttribute; @@ -65,21 +64,11 @@ public class ShapeRenderProgram extends Program { private final Uniform1Int useTextureUniform; private final Uniform1Int textureSlotUniform; - public ShapeRenderProgram( - String[] vertexShaderResources, - String[] fragmentShaderResources - ) { - super( - new CombinedShader( - attachVertexShader(vertexShaderResources) - ), - new CombinedShader( - attachFragmentShader(fragmentShaderResources) - ) - ); + public ShapeRenderProgram(String[] vertexShaderResources, String[] fragmentShaderResources) { + super(new CombinedShader(attachVertexShader(vertexShaderResources)), + new CombinedShader(attachFragmentShader(fragmentShaderResources))); - this.finalTransformUniform = getUniform(FINAL_TRANSFORM_UNIFORM_NAME) - .as4Matrix(); + this.finalTransformUniform = getUniform(FINAL_TRANSFORM_UNIFORM_NAME).as4Matrix(); this.positionsAttribute = getAttribute(POSITIONS_ATTRIBUTE_NAME).asVertexArray(); @@ -89,11 +78,9 @@ public class ShapeRenderProgram extends Program { this.textureCoordsAttribute = getAttribute(TEXTURE_COORDS_ATTRIBUTE_NAME).asVertexArray(); - this.useTextureUniform = getUniform(USE_TEXTURE_UNIFORM_NAME) - .as1Int(); + this.useTextureUniform = getUniform(USE_TEXTURE_UNIFORM_NAME).as1Int(); - this.textureSlotUniform = getUniform(TEXTURE_SLOT_UNIFORM_NAME) - .as1Int(); + this.textureSlotUniform = getUniform(TEXTURE_SLOT_UNIFORM_NAME).as1Int(); } private static String[] attachVertexShader(String[] others) { @@ -104,10 +91,7 @@ public class ShapeRenderProgram extends Program { return ObjectArrays.concat(SHAPE_FRAGMENT_SHADER_RESOURCE, others); } - public void render( - ShapeRenderHelper helper, - Shape shape - ) { + public void render(ShapeRenderHelper helper, Shape shape) { use(); configure(helper); @@ -116,7 +100,7 @@ public class ShapeRenderProgram extends Program { try { enableAttributes(); - for (FaceGroup group : shape.getGroups()) { + for (ShapePartGroup group : shape.getGroups()) { renderFaceGroup(group); } } finally { @@ -145,34 +129,13 @@ public class ShapeRenderProgram extends Program { int vertexStride = getBytesPerVertex(); int offset = 0; - positionsAttribute.set( - 3, - GL11.GL_FLOAT, - false, - vertexStride, - vertices, - offset - ); + positionsAttribute.set(3, GL11.GL_FLOAT, false, vertexStride, vertices, offset); offset += 3 * Float.BYTES; - colorsAttribute.set( - 4, - GL11.GL_FLOAT, - false, - vertexStride, - vertices, - offset - ); + colorsAttribute.set(4, GL11.GL_FLOAT, false, vertexStride, vertices, offset); offset += 4 * Float.BYTES; - textureCoordsAttribute.set( - 2, - GL11.GL_FLOAT, - false, - vertexStride, - vertices, - offset - ); + textureCoordsAttribute.set(2, GL11.GL_FLOAT, false, vertexStride, vertices, offset); offset += 2 * Float.BYTES; return offset; @@ -182,7 +145,7 @@ public class ShapeRenderProgram extends Program { indices.bind(BindTarget.ELEMENT_ARRAY); } - protected void renderFaceGroup(FaceGroup group) { + protected void renderFaceGroup(ShapePartGroup group) { TexturePrimitive texture = group.getTexture(); if (texture != null) { @@ -193,12 +156,8 @@ public class ShapeRenderProgram extends Program { useTextureUniform.set(0); } - GL11.glDrawElements( - GL11.GL_TRIANGLES, - group.getIndexCount(), - GL11.GL_UNSIGNED_SHORT, - group.getByteOffsetOfIndices() - ); + GL11.glDrawElements(GL11.GL_TRIANGLES, group.getIndexCount(), GL11.GL_UNSIGNED_SHORT, + group.getByteOffsetOfIndices()); } public int getBytesPerVertex() { @@ -206,12 +165,12 @@ public class ShapeRenderProgram extends Program { } public void preprocess(Shape shape) { - for (Face face : shape.getFaces()) { + for (ShapePart face : shape.getParts()) { applySprites(face); } } - private void applySprites(Face face) { + private void applySprites(ShapePart face) { if (face.getTexture() == null) return; @@ -220,13 +179,9 @@ public class ShapeRenderProgram extends Program { Sprite sprite = face.getTexture().getSprite(); for (int i = 0; i < face.getVertexCount(); i++) { - int offset = vertices.position() + i * getBytesPerVertex() + (3 * Float.BYTES + - 4 * Float.BYTES); + int offset = vertices.position() + i * getBytesPerVertex() + (3 * Float.BYTES + 4 * Float.BYTES); - v.set( - vertices.getFloat(offset + 0 * Float.BYTES), - vertices.getFloat(offset + 1 * Float.BYTES) - ); + v.set(vertices.getFloat(offset + 0 * Float.BYTES), vertices.getFloat(offset + 1 * Float.BYTES)); v.mul(sprite.getSize()).add(sprite.getStart()); @@ -244,34 +199,11 @@ public class ShapeRenderProgram extends Program { } public static interface VertexBuilder { - VertexBuilder addVertex( - float x, - float y, - float z, - float r, - float g, - float b, - float tx, - float ty - ); + VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float tx, float ty); - VertexBuilder addVertex( - float x, - float y, - float z, - float r, - float g, - float b, - float a, - float tx, - float ty - ); + VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float a, float tx, float ty); - VertexBuilder addVertex( - Vec3 position, - Vec4 colorMultiplier, - Vec2 textureCoords - ); + VertexBuilder addVertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords); ByteBuffer assemble(); } @@ -293,84 +225,35 @@ public class ShapeRenderProgram extends Program { private final List vertices = new ArrayList<>(); @Override - public VertexBuilder addVertex( - float x, - float y, - float z, - float r, - float g, - float b, - float a, - float tx, - float ty - ) { - vertices.add( - new Vertex( - new Vec3(x, y, z), - new Vec4(r, g, b, a), - new Vec2(tx, ty) - ) - ); + public VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float a, float tx, + float ty) { + vertices.add(new Vertex(new Vec3(x, y, z), new Vec4(r, g, b, a), new Vec2(tx, ty))); return this; } @Override - public VertexBuilder addVertex( - float x, - float y, - float z, - float r, - float g, - float b, - float tx, - float ty - ) { - vertices.add( - new Vertex( - new Vec3(x, y, z), - new Vec4(r, g, b, 1f), - new Vec2(tx, ty) - ) - ); + public VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float tx, float ty) { + vertices.add(new Vertex(new Vec3(x, y, z), new Vec4(r, g, b, 1f), new Vec2(tx, ty))); return this; } @Override - public VertexBuilder addVertex( - Vec3 position, - Vec4 colorMultiplier, - Vec2 textureCoords - ) { - vertices.add( - new Vertex( - new Vec3(position), - new Vec4(colorMultiplier), - new Vec2(textureCoords) - ) - ); + public VertexBuilder addVertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) { + vertices.add(new Vertex(new Vec3(position), new Vec4(colorMultiplier), new Vec2(textureCoords))); return this; } @Override public ByteBuffer assemble() { - ByteBuffer result = BufferUtils.createByteBuffer( - DEFAULT_BYTES_PER_VERTEX * vertices.size() - ); + ByteBuffer result = BufferUtils.createByteBuffer(DEFAULT_BYTES_PER_VERTEX * vertices.size()); for (Vertex v : vertices) { - result - .putFloat(v.position.x) - .putFloat(v.position.y) - .putFloat(v.position.z) - .putFloat(v.colorMultiplier.x) - .putFloat(v.colorMultiplier.y) - .putFloat(v.colorMultiplier.z) - .putFloat(v.colorMultiplier.w) - .putFloat(v.textureCoords.x) - .putFloat(v.textureCoords.y); + result.putFloat(v.position.x).putFloat(v.position.y).putFloat(v.position.z) + .putFloat(v.colorMultiplier.x).putFloat(v.colorMultiplier.y).putFloat(v.colorMultiplier.z) + .putFloat(v.colorMultiplier.w).putFloat(v.textureCoords.x).putFloat(v.textureCoords.y); } result.flip(); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java index 7ddd5d6..92d9872 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java @@ -24,7 +24,7 @@ import glm.vec._3.Vec3; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.backend.Usage; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class Shapes { @@ -50,7 +50,7 @@ public class Shapes { boolean flip ) { - Face top = Faces.createRectangle( + ShapePart top = ShapeParts.createRectangle( program, topTexture, colorMultiplier, @@ -60,7 +60,7 @@ public class Shapes { flip ); - Face bottom = Faces.createRectangle( + ShapePart bottom = ShapeParts.createRectangle( program, bottomTexture, colorMultiplier, @@ -70,7 +70,7 @@ public class Shapes { flip ); - Face north = Faces.createRectangle( + ShapePart north = ShapeParts.createRectangle( program, northTexture, colorMultiplier, @@ -80,7 +80,7 @@ public class Shapes { flip ); - Face south = Faces.createRectangle( + ShapePart south = ShapeParts.createRectangle( program, southTexture, colorMultiplier, @@ -90,7 +90,7 @@ public class Shapes { flip ); - Face east = Faces.createRectangle( + ShapePart east = ShapeParts.createRectangle( program, eastTexture, colorMultiplier, @@ -100,7 +100,7 @@ public class Shapes { flip ); - Face west = Faces.createRectangle( + ShapePart west = ShapeParts.createRectangle( program, westTexture, colorMultiplier, @@ -165,16 +165,16 @@ public class Shapes { public PppBuilder( ShapeRenderProgram program, - Map textureMap + Map textureMap ) { this( program, - textureMap.get(BlockFace.TOP), - textureMap.get(BlockFace.BOTTOM), - textureMap.get(BlockFace.NORTH), - textureMap.get(BlockFace.SOUTH), - textureMap.get(BlockFace.EAST), - textureMap.get(BlockFace.WEST) + textureMap.get(AbsFace.POS_Z), + textureMap.get(AbsFace.NEG_Z), + textureMap.get(AbsFace.POS_X), + textureMap.get(AbsFace.NEG_X), + textureMap.get(AbsFace.NEG_Y), + textureMap.get(AbsFace.POS_Y) ); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/StaticModel.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/StaticModel.java index 4c489d3..8c5ae87 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/StaticModel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/StaticModel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.model; import java.util.ArrayList; @@ -30,10 +30,7 @@ public class StaticModel extends Model { private final Mat4[] transforms; - public StaticModel( - Renderable[] parts, - Mat4[] transforms - ) { + public StaticModel(Renderable[] parts, Mat4[] transforms) { super(parts); this.transforms = transforms; } @@ -55,19 +52,14 @@ public class StaticModel extends Model { protected Builder() { } - public Builder addPart( - Renderable part, - Mat4 transform - ) { + public Builder addPart(Renderable part, Mat4 transform) { parts.add(Objects.requireNonNull(part, "part")); transforms.add(Objects.requireNonNull(transform, "transform")); return this; } - public Builder addPart( - Renderable part - ) { + public Builder addPart(Renderable part) { return addPart(part, IDENTITY); } @@ -78,7 +70,7 @@ public class StaticModel extends Model { private Mat4[] getTransforms() { return transforms.toArray(new Mat4[transforms.size()]); } - + public StaticModel build() { return new StaticModel(getParts(), getTransforms()); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Atlases.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Atlases.java index 94ed270..7ebe8fb 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Atlases.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Atlases.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; import java.io.IOException; @@ -87,11 +87,8 @@ public class Atlases { editor.draw(data, nextX, nextY); - Sprite result = new Sprite( - getPrimitive(), - toPrimitiveCoords(nextX, nextY), - toPrimitiveCoords(width, height) - ); + Sprite result = new Sprite(getPrimitive(), toPrimitiveCoords(nextX, nextY), + toPrimitiveCoords(width, height)); nextX += width; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java index a4f2881..a54ca51 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java @@ -21,7 +21,7 @@ package ru.windcorp.progressia.client.graphics.texture; import java.util.Map; import glm.vec._2.Vec2; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class ComplexTexture { @@ -54,14 +54,14 @@ public class ComplexTexture { ); } - public Map getCuboidTextures( + public Map getCuboidTextures( int x, int y, int width, int height, int depth ) { - return BlockFace.mapToFaces( + return AbsFace.mapToFaces( get( x + depth + width, y + height + depth, @@ -86,7 +86,7 @@ public class ComplexTexture { ); } - public Map getCuboidTextures( + public Map getCuboidTextures( int x, int y, int size diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTexture.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTexture.java index d772faa..f631f54 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTexture.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTexture.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; public class SimpleTexture extends Texture { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTextures.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTextures.java index 12db086..b547a8a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTextures.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTextures.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; import java.io.IOException; @@ -44,9 +44,7 @@ public class SimpleTextures { try { TextureDataEditor data = TextureLoader.loadPixels(resource, SETTINGS); - return new SimpleTexture( - new Sprite(new TexturePrimitive(data.getData())) - ); + return new SimpleTexture(new Sprite(new TexturePrimitive(data.getData()))); } catch (IOException e) { throw CrashReports.report(e, "Could not load texture %s", resource); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Sprite.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Sprite.java index fc13896..388c2dc 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Sprite.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Sprite.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; import java.util.Objects; @@ -38,14 +38,8 @@ public class Sprite { } public Sprite(TexturePrimitive primitive) { - this( - primitive, - ORIGIN, - new Vec2( - primitive.getWidth() / (float) primitive.getBufferWidth(), - primitive.getHeight() / (float) primitive.getBufferHeight() - ) - ); + this(primitive, ORIGIN, new Vec2(primitive.getWidth() / (float) primitive.getBufferWidth(), + primitive.getHeight() / (float) primitive.getBufferHeight())); } public TexturePrimitive getPrimitive() { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Texture.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Texture.java index a4d89bf..3041679 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Texture.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Texture.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; public abstract class Texture { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureData.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureData.java index 0453984..891111b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureData.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureData.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; import static org.lwjgl.opengl.GL11.*; @@ -35,14 +35,8 @@ class TextureData { private final int width; private final int height; - public TextureData( - ByteBuffer data, - int bufferWidth, - int bufferHeight, - int width, - int height, - TextureSettings settings - ) { + public TextureData(ByteBuffer data, int bufferWidth, int bufferHeight, int width, int height, + TextureSettings settings) { this.data = data; this.width = width; this.height = height; @@ -66,16 +60,15 @@ class TextureData { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D( - GL_TEXTURE_2D, // Load 2D image - 0, // Not mipmapped - GL_RGBA, // Use RGBA - bufferWidth, // Width - bufferHeight, // Height - 0, // No border - GL_RGBA, // Use RGBA (required) - GL_UNSIGNED_BYTE, // Use unsigned bytes - data // Data buffer + glTexImage2D(GL_TEXTURE_2D, // Load 2D image + 0, // Not mipmapped + GL_RGBA, // Use RGBA + bufferWidth, // Width + bufferHeight, // Height + 0, // No border + GL_RGBA, // Use RGBA (required) + GL_UNSIGNED_BYTE, // Use unsigned bytes + data // Data buffer ); return handle; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureDataEditor.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureDataEditor.java index 7079f59..e52365c 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureDataEditor.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureDataEditor.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; import static ru.windcorp.progressia.client.graphics.texture.TextureUtil.BYTES_PER_PIXEL; @@ -28,21 +28,10 @@ public class TextureDataEditor { protected final TextureData data; - public TextureDataEditor( - int bufferWidth, - int bufferHeight, - int contentWidth, - int contentHeight, - TextureSettings settings - ) { - this.data = new TextureData( - BufferUtils.createByteBuffer(bufferWidth * bufferHeight * 4), - bufferWidth, - bufferHeight, - contentWidth, - contentHeight, - settings - ); + public TextureDataEditor(int bufferWidth, int bufferHeight, int contentWidth, int contentHeight, + TextureSettings settings) { + this.data = new TextureData(BufferUtils.createByteBuffer(bufferWidth * bufferHeight * 4), bufferWidth, + bufferHeight, contentWidth, contentHeight, settings); } public TextureDataEditor(TextureData data) { @@ -61,21 +50,13 @@ public class TextureDataEditor { TextureData t = getData(); ByteBuffer fromBuffer = getBuffer(); - ByteBuffer toBuffer = BufferUtils.createByteBuffer( - fromBuffer.capacity() - ); + ByteBuffer toBuffer = BufferUtils.createByteBuffer(fromBuffer.capacity()); copy(fromBuffer, 0, fromBuffer.capacity(), toBuffer); toBuffer.clear(); - return new TextureData( - toBuffer, - t.getBufferWidth(), - t.getBufferHeight(), - t.getContentWidth(), - t.getContentHeight(), - t.getSettings() - ); + return new TextureData(toBuffer, t.getBufferWidth(), t.getBufferHeight(), t.getContentWidth(), + t.getContentHeight(), t.getSettings()); } public TextureData createSnapshot(TextureData output) { @@ -114,16 +95,7 @@ public class TextureDataEditor { return getData().getSettings(); } - public void draw( - ByteBuffer src, - int srcWidth, - int srcX, - int srcY, - int dstX, - int dstY, - int width, - int height - ) { + public void draw(ByteBuffer src, int srcWidth, int srcX, int srcY, int dstX, int dstY, int width, int height) { ByteBuffer dst = getBuffer(); int position = src.position(); @@ -148,77 +120,20 @@ public class TextureDataEditor { } } - public void draw( - TextureData source, - int srcX, - int srcY, - int dstX, - int dstY, - int width, - int height - ) { - draw( - source.getData(), - source.getBufferWidth(), - srcX, - srcY, - dstX, - dstY, - width, - height - ); + public void draw(TextureData source, int srcX, int srcY, int dstX, int dstY, int width, int height) { + draw(source.getData(), source.getBufferWidth(), srcX, srcY, dstX, dstY, width, height); } - public void draw( - TextureData source, - int dstX, - int dstY - ) { - draw( - source, - 0, - 0, - dstX, - dstY, - source.getContentWidth(), - source.getContentHeight() - ); + public void draw(TextureData source, int dstX, int dstY) { + draw(source, 0, 0, dstX, dstY, source.getContentWidth(), source.getContentHeight()); } - public void draw( - TextureDataEditor source, - int srcX, - int srcY, - int dstX, - int dstY, - int width, - int height - ) { - draw( - source.getData(), - srcX, - srcY, - dstX, - dstY, - width, - height - ); + public void draw(TextureDataEditor source, int srcX, int srcY, int dstX, int dstY, int width, int height) { + draw(source.getData(), srcX, srcY, dstX, dstY, width, height); } - public void draw( - TextureDataEditor source, - int dstX, - int dstY - ) { - draw( - source, - 0, - 0, - dstX, - dstY, - source.getContentWidth(), - source.getContentHeight() - ); + public void draw(TextureDataEditor source, int dstX, int dstY) { + draw(source, 0, 0, dstX, dstY, source.getContentWidth(), source.getContentHeight()); } public void setPixel(int x, int y, int color) { @@ -237,12 +152,7 @@ public class TextureDataEditor { buffer.limit(buffer.position() + length * BYTES_PER_PIXEL); } - private static void copy( - ByteBuffer src, - int srcStart, - int srcEnd, - ByteBuffer dst - ) { + private static void copy(ByteBuffer src, int srcStart, int srcEnd, ByteBuffer dst) { int position = src.position(); int limit = src.limit(); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureLoader.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureLoader.java index 18f2326..d406c65 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureLoader.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureLoader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; import java.awt.Graphics2D; @@ -31,11 +31,7 @@ import ru.windcorp.progressia.common.util.BinUtil; public class TextureLoader { - public static TextureDataEditor loadPixels( - InputStream compressed, - TextureSettings settings - ) - throws IOException { + public static TextureDataEditor loadPixels(InputStream compressed, TextureSettings settings) throws IOException { BufferedImage readResult = ImageIO.read(compressed); int width = readResult.getWidth(); @@ -44,10 +40,7 @@ public class TextureLoader { int bufferWidth = BinUtil.roundToGreaterPowerOf2(width); int bufferHeight = BinUtil.roundToGreaterPowerOf2(height); - WritableRaster raster = TextureUtil.createRaster( - bufferWidth, - bufferHeight - ); + WritableRaster raster = TextureUtil.createRaster(bufferWidth, bufferHeight); BufferedImage canvas = TextureUtil.createCanvas(raster); @@ -56,49 +49,22 @@ public class TextureLoader { try { g.setColor(TextureUtil.CANVAS_BACKGROUND); g.fillRect(0, 0, bufferWidth, bufferHeight); - g.drawImage( - readResult, - 0, - 0, - width, - height, - 0, - height, - width, - 0, // Flip the image - null - ); + g.drawImage(readResult, 0, 0, width, height, 0, height, width, 0, // Flip + // the + // image + null); } finally { g.dispose(); } - TextureDataEditor result = new TextureDataEditor( - bufferWidth, - bufferHeight, - width, - height, - settings - ); + TextureDataEditor result = new TextureDataEditor(bufferWidth, bufferHeight, width, height, settings); - result.draw( - TextureUtil.extractBytes(raster), - bufferWidth, - 0, - 0, - 0, - 0, - width, - height - ); + result.draw(TextureUtil.extractBytes(raster), bufferWidth, 0, 0, 0, 0, width, height); return result; } - public static TextureDataEditor loadPixels( - Resource resource, - TextureSettings settings - ) - throws IOException { + public static TextureDataEditor loadPixels(Resource resource, TextureSettings settings) throws IOException { return loadPixels(resource.getInputStream(), settings); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TexturePrimitive.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TexturePrimitive.java index a1895bb..62c981b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TexturePrimitive.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TexturePrimitive.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; import static org.lwjgl.opengl.GL11.*; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureSettings.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureSettings.java index 3dd43a4..0b75742 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureSettings.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureSettings.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; public class TextureSettings { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureUtil.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureUtil.java index ea0fdee..72eab34 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureUtil.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureUtil.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.texture; import java.awt.Color; @@ -39,35 +39,28 @@ public class TextureUtil { public static final Color CANVAS_BACKGROUND = new Color(0, true); - public static final ColorModel COLOR_MODEL = new ComponentColorModel( - ColorSpace.getInstance(ColorSpace.CS_sRGB), // Use RGB - null, // Use every bit - true, // Has alpha - false, // Not premultiplied - Transparency.TRANSLUCENT, // Can have any alpha - DataBuffer.TYPE_BYTE // Store bytewise + public static final ColorModel COLOR_MODEL = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), // Use + // RGB + null, // Use every bit + true, // Has alpha + false, // Not premultiplied + Transparency.TRANSLUCENT, // Can have any alpha + DataBuffer.TYPE_BYTE // Store bytewise ); private static final Hashtable BUFFERED_IMAGE_PROPERTIES = new Hashtable<>(); - public static WritableRaster createRaster( - int bufferWidth, - int bufferHeight - ) { - return Raster.createInterleavedRaster( - DataBuffer.TYPE_BYTE, // Storage model - bufferWidth, // Buffer width - bufferHeight, // Buffer height - BYTES_PER_PIXEL, // ARGB - null // Location (here (0; 0)) + public static WritableRaster createRaster(int bufferWidth, int bufferHeight) { + return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, // Storage + // model + bufferWidth, // Buffer width + bufferHeight, // Buffer height + BYTES_PER_PIXEL, // ARGB + null // Location (here (0; 0)) ); } - public static WritableRaster createRaster( - ByteBuffer buffer, - int bufferWidth, - int bufferHeight - ) { + public static WritableRaster createRaster(ByteBuffer buffer, int bufferWidth, int bufferHeight) { final int bands = BYTES_PER_PIXEL; byte[] bytes = new byte[bufferWidth * bufferHeight * bands]; @@ -77,23 +70,21 @@ public class TextureUtil { DataBufferByte dataBuffer = new DataBufferByte(bytes, bytes.length); - return Raster.createInterleavedRaster( - dataBuffer, // The buffer - bufferWidth, // Buffer width - bufferHeight, // Buffer height - bands * bufferWidth, // Scanline stride - bands, // Pixel stride - new int[] { 0, 1, 2, 3 }, // Band offsets - null // Location (here (0; 0)) + return Raster.createInterleavedRaster(dataBuffer, // The buffer + bufferWidth, // Buffer width + bufferHeight, // Buffer height + bands * bufferWidth, // Scanline stride + bands, // Pixel stride + new int[] { 0, 1, 2, 3 }, // Band offsets + null // Location (here (0; 0)) ); } public static BufferedImage createCanvas(WritableRaster raster) { - return new BufferedImage( - COLOR_MODEL, // Color model - raster, // Backing raster - false, // Raster is not premultipied - BUFFERED_IMAGE_PROPERTIES // Properties + return new BufferedImage(COLOR_MODEL, // Color model + raster, // Backing raster + false, // Raster is not premultipied + BUFFERED_IMAGE_PROPERTIES // Properties ); } @@ -107,10 +98,7 @@ public class TextureUtil { return buffer; } - public static ByteBuffer extractBytes( - WritableRaster raster, - ByteBuffer output - ) { + public static ByteBuffer extractBytes(WritableRaster raster, ByteBuffer output) { byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData(); output.put(data); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java index 46b551c..9c30a49 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java @@ -29,6 +29,9 @@ import glm.mat._4.Mat4; import glm.vec._3.Vec3; import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.world.Camera.Anchor.Mode; +import ru.windcorp.progressia.client.world.entity.NPedModel; +import ru.windcorp.progressia.common.util.Matrices; +import ru.windcorp.progressia.common.util.Vectors; public class Camera { @@ -60,13 +63,13 @@ public class Camera { } } - void getCameraPosition(Vec3 output); + Vec3 getCameraPosition(Vec3 output); - void getCameraVelocity(Vec3 output); + Vec3 getCameraVelocity(Vec3 output); - float getCameraYaw(); - - float getCameraPitch(); + Vec3 getLookingAt(Vec3 output); + + Vec3 getUpVector(Vec3 output); Collection getCameraModes(); @@ -84,14 +87,11 @@ public class Camera { */ private final Vec3 lastAnchorPosition = new Vec3(); - private float lastAnchorYaw; - private float lastAnchorPitch; + private final Vec3 lastAnchorLookingAt = new Vec3(); + private final Vec3 lastAnchorUpVector = new Vec3(); private final Mat4 lastCameraMatrix = new Mat4(); - private final Vec3 lastAnchorLookingAt = new Vec3(); - private final Vec3 lastAnchorUp = new Vec3(); - { invalidateCache(); } @@ -108,6 +108,9 @@ public class Camera { */ public void apply(WorldRenderHelper helper) { + if (NPedModel.flag) { +// System.out.println("Camera.apply()"); + } applyPerspective(helper); rotateCoordinateSystem(helper); @@ -149,26 +152,34 @@ public class Camera { } private void applyDirection(WorldRenderHelper helper) { - float pitch = anchor.getCameraPitch(); - float yaw = anchor.getCameraYaw(); + anchor.getLookingAt(lastAnchorLookingAt); + anchor.getUpVector(lastAnchorUpVector); - helper.pushViewTransform() - .rotateY(-pitch) - .rotateZ(-yaw); + lookAt(helper.pushViewTransform()); + } - this.lastAnchorYaw = yaw; - this.lastAnchorPitch = pitch; - - this.lastAnchorLookingAt.set( - cos(pitch) * cos(yaw), - cos(pitch) * sin(yaw), - sin(pitch) - ); - this.lastAnchorUp.set( - cos(pitch + PI_F / 2) * cos(yaw), - cos(pitch + PI_F / 2) * sin(yaw), - sin(pitch + PI_F / 2) + private void lookAt(Mat4 result) { + Vec3 f = this.lastAnchorLookingAt; + Vec3 s = Vectors.grab3(); + Vec3 u = Vectors.grab3(); + + f.cross(this.lastAnchorUpVector, s); + s.normalize(); + + s.cross(f, u); + + Mat4 workspace = Matrices.grab4(); + workspace.set( + +f.x, -s.x, +u.x, 0, + +f.y, -s.y, +u.y, 0, + +f.z, -s.z, +u.z, 0, + 0, 0, 0, 1 ); + result.mul(workspace); + Matrices.release(workspace); + + Vectors.release(s); + Vectors.release(u); } private void applyPosition(WorldRenderHelper helper) { @@ -247,8 +258,6 @@ public class Camera { private void invalidateCache() { this.lastAnchorPosition.set(Float.NaN); - this.lastAnchorYaw = Float.NaN; - this.lastAnchorPitch = Float.NaN; this.lastCameraMatrix.set( Float.NaN, @@ -270,7 +279,7 @@ public class Camera { ); this.lastAnchorLookingAt.set(Float.NaN); - this.lastAnchorUp.set(Float.NaN); + this.lastAnchorUpVector.set(Float.NaN); } public Anchor.Mode getMode() { @@ -289,14 +298,6 @@ public class Camera { return currentModeIndex; } - public float getLastAnchorYaw() { - return lastAnchorYaw; - } - - public float getLastAnchorPitch() { - return lastAnchorPitch; - } - public Vec3 getLastAnchorPosition() { return lastAnchorPosition; } @@ -310,7 +311,7 @@ public class Camera { } public Vec3 getLastAnchorUp() { - return lastAnchorUp; + return lastAnchorUpVector; } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java index d11ea92..53b7af5 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.world; import java.util.Collection; @@ -39,44 +39,45 @@ public class EntityAnchor implements Anchor { this.model = model; this.modes = ImmutableList.of( - // From viewpoint / first person - Mode.of(v -> v.set(0), m -> { - }), + // From viewpoint / first person + Mode.of(v -> v.set(0), m -> { + }), - // Third person, looking forward - Mode.of( - v -> v.set(-3.5f, +0.5f, 0), - m -> { - } - ), + // Third person, looking forward + Mode.of(v -> v.set(-3.5f, +0.5f, 0), m -> { + }), - // Third person, looking back - Mode.of( - v -> v.set(-3.5f, 0, 0), - m -> m.rotateZ((float) Math.PI) - ) - ); + // Third person, looking back + Mode.of(v -> v.set(-3.5f, 0, 0), m -> m.rotateZ((float) Math.PI))); } @Override - public void getCameraPosition(Vec3 output) { + public Vec3 getCameraPosition(Vec3 output) { + if (output == null) output = new Vec3(); model.getViewPoint(output); - output.add(entity.getPosition()); + output.add(model.getPosition()); + return output; } @Override - public void getCameraVelocity(Vec3 output) { + public Vec3 getCameraVelocity(Vec3 output) { + if (output == null) output = new Vec3(); output.set(entity.getVelocity()); + return output; } @Override - public float getCameraYaw() { - return entity.getYaw(); + public Vec3 getLookingAt(Vec3 output) { + if (output == null) output = new Vec3(); + model.getLookingAt(output); + return output; } - + @Override - public float getCameraPitch() { - return entity.getPitch(); + public Vec3 getUpVector(Vec3 output) { + if (output == null) output = new Vec3(); + model.getUpVector(output); + return output; } @Override diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java index 50709ac..bfe8658 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.world; import java.util.ArrayList; @@ -41,6 +41,8 @@ import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.collision.Collideable; import ru.windcorp.progressia.common.collision.colliders.Collider; import ru.windcorp.progressia.common.util.FloatMathUtil; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.test.CollisionModelRenderer; import ru.windcorp.progressia.test.TestPlayerControls; @@ -112,11 +114,11 @@ public class LayerWorld extends Layer { tmp_testControls.applyPlayerControls(); - for (EntityData data : this.client.getWorld().getData().getEntities()) { + this.client.getWorld().getData().getEntities().forEach(data -> { tmp_applyFriction(data, tickLength); tmp_applyGravity(data, tickLength); tmp_renderCollisionModel(data); - } + }); } catch (Throwable e) { e.printStackTrace(); System.err.println("OLEGSHA is to blame. Tell him he vry stupiDD!!"); @@ -134,12 +136,8 @@ public class LayerWorld extends Layer { tmp_collideableList.clear(); tmp_collideableList.addAll(this.client.getWorld().getData().getEntities()); - Collider.performCollisions( - tmp_collideableList, - this.client.getWorld().getData(), - tickLength, - tmp_colliderWorkspace - ); + Collider.performCollisions(tmp_collideableList, this.client.getWorld().getData(), tickLength, + tmp_colliderWorkspace); } private static final Renderable SELECTION_BOX = tmp_createSelectionBox(); @@ -168,26 +166,14 @@ public class LayerWorld extends Layer { for (float phi = 0; phi < 2 * FloatMathUtil.PI_F; phi += FloatMathUtil.PI_F / 2) { Mat4 rot = new Mat4().identity().rotateZ(phi).scale(scale); - b.addPart( - new PppBuilder(p, (Texture) null).setOrigin( - new Vec3(-f - 0.5f, -f - 0.5f, -f - 0.5f) - ).setSize(f, f, 2 * f + 1).setColorMultiplier(color).create(), - rot - ); + b.addPart(new PppBuilder(p, (Texture) null).setOrigin(new Vec3(-f - 0.5f, -f - 0.5f, -f - 0.5f)) + .setSize(f, f, 2 * f + 1).setColorMultiplier(color).create(), rot); - b.addPart( - new PppBuilder(p, (Texture) null).setOrigin( - new Vec3(-f - 0.5f, -0.5f, -f - 0.5f) - ).setSize(f, 1, f).setColorMultiplier(color).create(), - rot - ); + b.addPart(new PppBuilder(p, (Texture) null).setOrigin(new Vec3(-f - 0.5f, -0.5f, -f - 0.5f)) + .setSize(f, 1, f).setColorMultiplier(color).create(), rot); - b.addPart( - new PppBuilder(p, (Texture) null).setOrigin( - new Vec3(-f - 0.5f, -0.5f, +0.5f) - ).setSize(f, 1, f).setColorMultiplier(color).create(), - rot - ); + b.addPart(new PppBuilder(p, (Texture) null).setOrigin(new Vec3(-f - 0.5f, -0.5f, +0.5f)).setSize(f, 1, f) + .setColorMultiplier(color).create(), rot); } return b.build(); @@ -199,16 +185,25 @@ public class LayerWorld extends Layer { entity.getVelocity().mul((float) Math.exp(-FRICTION_COEFF / entity.getCollisionMass() * tickLength)); } - private static final float MC_g = Units.get("32 m/s^2"); - private static final float IRL_g = Units.get("9.8 m/s^2"); - private void tmp_applyGravity(EntityData entity, float tickLength) { + GravityModel gm = ClientState.getInstance().getWorld().getData().getGravityModel(); + + Vec3 upVector = Vectors.grab3(); + gm.getUp(entity.getPosition(), upVector); + entity.changeUpVector(upVector); + Vectors.release(upVector); + if (ClientState.getInstance().getLocalPlayer().getEntity() == entity && tmp_testControls.isFlying()) { return; } - final float gravitationalAcceleration = tmp_testControls.useMinecraftGravity() ? MC_g : IRL_g; - entity.getVelocity().add(0, 0, -gravitationalAcceleration * tickLength); + Vec3 gravitationalAcceleration = Vectors.grab3(); + gm.getGravity(entity.getPosition(), gravitationalAcceleration); + + gravitationalAcceleration.mul(tickLength); + entity.getVelocity().add(gravitationalAcceleration); + + Vectors.release(gravitationalAcceleration); } @Override diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java index 620185b..7a4443a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.world; import ru.windcorp.progressia.client.Client; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java index cd4ba29..559e432 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.world; import glm.vec._2.Vec2; @@ -23,13 +23,13 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.world.WorldRender; import ru.windcorp.progressia.common.world.BlockRay; -import ru.windcorp.progressia.common.world.block.BlockFace; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class Selection { private final Vec3i block = new Vec3i(); - private BlockFace surface = null; + private AbsFace surface = null; private final Vec2 pointOnSurface = new Vec2(0.5f, 0.5f); private final Vec3 point = new Vec3(); @@ -38,10 +38,9 @@ public class Selection { private BlockRay ray = new BlockRay(); public void update(WorldRender world, EntityData player) { - Vec3 direction = new Vec3(); Vec3 start = new Vec3(); - - player.getLookingAtVector(direction); + Vec3 direction = player.getLookingAt(); + world.getEntityRenderable(player).getViewPoint(start); start.add(player.getPosition()); @@ -71,7 +70,7 @@ public class Selection { return exists ? point : null; } - public BlockFace getSurface() { + public AbsFace getSurface() { return exists ? surface : null; } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderHelper.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderHelper.java index de17238..e677eaf 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderHelper.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderHelper.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.world; import glm.mat._4.Mat4; @@ -24,10 +24,7 @@ import ru.windcorp.progressia.common.util.StashingStack; public class WorldRenderHelper extends ShapeRenderHelper { - private final StashingStack viewTransformStack = new StashingStack<>( - TRANSFORM_STACK_SIZE, - Mat4::new - ); + private final StashingStack viewTransformStack = new StashingStack<>(TRANSFORM_STACK_SIZE, Mat4::new); { viewTransformStack.push().identity(); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java index 5e55297..8fb000f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.graphics.world; import java.nio.ByteBuffer; @@ -33,7 +33,7 @@ import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; import ru.windcorp.progressia.client.graphics.backend.shaders.attributes.*; import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.*; -import ru.windcorp.progressia.client.graphics.model.Face; +import ru.windcorp.progressia.client.graphics.model.ShapePart; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; @@ -44,10 +44,8 @@ public class WorldRenderProgram extends ShapeRenderProgram { private static WorldRenderProgram def = null; public static void init() { - def = new WorldRenderProgram( - new String[] { "WorldDefault.vertex.glsl" }, - new String[] { "WorldDefault.fragment.glsl" } - ); + def = new WorldRenderProgram(new String[] { "WorldDefault.vertex.glsl" }, + new String[] { "WorldDefault.fragment.glsl" }); } public static WorldRenderProgram getDefault() { @@ -55,33 +53,25 @@ public class WorldRenderProgram extends ShapeRenderProgram { } private static final int DEFAULT_BYTES_PER_VERTEX = 3 * Float.BYTES + // Position - 4 * Float.BYTES + // Color multiplier - 2 * Float.BYTES + // Texture coordinates - 3 * Float.BYTES; // Normals + 4 * Float.BYTES + // Color multiplier + 2 * Float.BYTES + // Texture coordinates + 3 * Float.BYTES; // Normals private static final String WORLD_VERTEX_SHADER_RESOURCE = "World.vertex.glsl"; private static final String WORLD_FRAGMENT_SHADER_RESOURCE = "World.fragment.glsl"; private static final String WORLD_TRANSFORM_UNIFORM_NAME = "worldTransform", - NORMALS_ATTRIBUTE_NAME = "inputNormals"; + NORMALS_ATTRIBUTE_NAME = "inputNormals"; private final Uniform4Matrix worldTransformUniform; private final AttributeVertexArray normalsAttribute; - public WorldRenderProgram( - String[] vertexShaderResources, - String[] fragmentShaderResources - ) { - super( - attachVertexShader(vertexShaderResources), - attachFragmentShader(fragmentShaderResources) - ); + public WorldRenderProgram(String[] vertexShaderResources, String[] fragmentShaderResources) { + super(attachVertexShader(vertexShaderResources), attachFragmentShader(fragmentShaderResources)); - this.worldTransformUniform = getUniform(WORLD_TRANSFORM_UNIFORM_NAME) - .as4Matrix(); + this.worldTransformUniform = getUniform(WORLD_TRANSFORM_UNIFORM_NAME).as4Matrix(); - this.normalsAttribute = getAttribute(NORMALS_ATTRIBUTE_NAME) - .asVertexArray(); + this.normalsAttribute = getAttribute(NORMALS_ATTRIBUTE_NAME).asVertexArray(); } private static String[] attachVertexShader(String[] others) { @@ -103,14 +93,7 @@ public class WorldRenderProgram extends ShapeRenderProgram { int vertexStride = getBytesPerVertex(); int offset = super.bindVertices(vertices); - normalsAttribute.set( - 3, - GL11.GL_FLOAT, - false, - vertexStride, - vertices, - offset - ); + normalsAttribute.set(3, GL11.GL_FLOAT, false, vertexStride, vertices, offset); offset += 3 * Float.BYTES; return offset; @@ -130,20 +113,19 @@ public class WorldRenderProgram extends ShapeRenderProgram { @Override public int getBytesPerVertex() { - return super.getBytesPerVertex() + - 3 * Float.BYTES; // Normals + return super.getBytesPerVertex() + 3 * Float.BYTES; // Normals } @Override public void preprocess(Shape shape) { super.preprocess(shape); - for (Face face : shape.getFaces()) { + for (ShapePart face : shape.getParts()) { computeNormals(face); } } - private void computeNormals(Face face) { + private void computeNormals(ShapePart face) { Vec3 a = Vectors.grab3(); Vec3 b = Vectors.grab3(); Vec3 c = Vectors.grab3(); @@ -171,34 +153,25 @@ public class WorldRenderProgram extends ShapeRenderProgram { Vectors.release(normal); } - private void computeOneNormal( - Vec3 a, - Vec3 b, - Vec3 c, - Vec3 normal - ) { + private void computeOneNormal(Vec3 a, Vec3 b, Vec3 c, Vec3 normal) { b.sub(a); c.sub(a); b.cross(c, normal); normal.normalize(); } - private void loadVertexPosition(Face face, int index, Vec3 result) { + private void loadVertexPosition(ShapePart face, int index, Vec3 result) { ByteBuffer vertices = face.getVertices(); int offset = vertices.position() + index * getBytesPerVertex(); - result.set( - vertices.getFloat(offset + 0 * Float.BYTES), - vertices.getFloat(offset + 1 * Float.BYTES), - vertices.getFloat(offset + 2 * Float.BYTES) - ); + result.set(vertices.getFloat(offset + 0 * Float.BYTES), vertices.getFloat(offset + 1 * Float.BYTES), + vertices.getFloat(offset + 2 * Float.BYTES)); } - private void saveVertexNormal(Face face, int index, Vec3 normal) { + private void saveVertexNormal(ShapePart face, int index, Vec3 normal) { ByteBuffer vertices = face.getVertices(); - int offset = vertices.position() + index * getBytesPerVertex() + (3 * Float.BYTES + - 4 * Float.BYTES + - 2 * Float.BYTES); + int offset = vertices.position() + index * getBytesPerVertex() + + (3 * Float.BYTES + 4 * Float.BYTES + 2 * Float.BYTES); vertices.putFloat(offset + 0 * Float.BYTES, normal.x); vertices.putFloat(offset + 1 * Float.BYTES, normal.y); @@ -231,87 +204,36 @@ public class WorldRenderProgram extends ShapeRenderProgram { private final List vertices = new ArrayList<>(); @Override - public VertexBuilder addVertex( - float x, - float y, - float z, - float r, - float g, - float b, - float tx, - float ty - ) { - vertices.add( - new Vertex( - new Vec3(x, y, z), - new Vec4(r, g, b, 1), - new Vec2(tx, ty) - ) - ); + public VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float tx, float ty) { + vertices.add(new Vertex(new Vec3(x, y, z), new Vec4(r, g, b, 1), new Vec2(tx, ty))); return this; } @Override - public VertexBuilder addVertex( - float x, - float y, - float z, - float r, - float g, - float b, - float a, - float tx, - float ty - ) { - vertices.add( - new Vertex( - new Vec3(x, y, z), - new Vec4(r, g, b, a), - new Vec2(tx, ty) - ) - ); + public VertexBuilder addVertex(float x, float y, float z, float r, float g, float b, float a, float tx, + float ty) { + vertices.add(new Vertex(new Vec3(x, y, z), new Vec4(r, g, b, a), new Vec2(tx, ty))); return this; } @Override - public VertexBuilder addVertex( - Vec3 position, - Vec4 colorMultiplier, - Vec2 textureCoords - ) { - vertices.add( - new Vertex( - new Vec3(position), - new Vec4(colorMultiplier), - new Vec2(textureCoords) - ) - ); + public VertexBuilder addVertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) { + vertices.add(new Vertex(new Vec3(position), new Vec4(colorMultiplier), new Vec2(textureCoords))); return this; } @Override public ByteBuffer assemble() { - ByteBuffer result = BufferUtils.createByteBuffer( - DEFAULT_BYTES_PER_VERTEX * vertices.size() - ); + ByteBuffer result = BufferUtils.createByteBuffer(DEFAULT_BYTES_PER_VERTEX * vertices.size()); for (Vertex v : vertices) { - result - .putFloat(v.position.x) - .putFloat(v.position.y) - .putFloat(v.position.z) - .putFloat(v.colorMultiplier.x) - .putFloat(v.colorMultiplier.y) - .putFloat(v.colorMultiplier.z) - .putFloat(v.colorMultiplier.w) - .putFloat(v.textureCoords.x) - .putFloat(v.textureCoords.y) - .putFloat(Float.NaN) - .putFloat(Float.NaN) - .putFloat(Float.NaN); + result.putFloat(v.position.x).putFloat(v.position.y).putFloat(v.position.z) + .putFloat(v.colorMultiplier.x).putFloat(v.colorMultiplier.y).putFloat(v.colorMultiplier.z) + .putFloat(v.colorMultiplier.w).putFloat(v.textureCoords.x).putFloat(v.textureCoords.y) + .putFloat(Float.NaN).putFloat(Float.NaN).putFloat(Float.NaN); } result.flip(); diff --git a/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java b/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java index b7c1f54..8e06d9f 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.localization; @FunctionalInterface diff --git a/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java b/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java index b61d000..e90ecd8 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.localization; import java.lang.ref.WeakReference; @@ -35,7 +35,7 @@ public class Localizer { private final Map langList; private final Collection> listeners = Collections - .synchronizedCollection(new LinkedList<>()); + .synchronizedCollection(new LinkedList<>()); // lang list must be in the same folder as .lang files public Localizer(String langFolder) { diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableString.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableString.java index a96d804..a1dfc92 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableString.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableString.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.localization; import java.lang.ref.WeakReference; @@ -34,7 +34,7 @@ public abstract class MutableString { protected String data; protected final Collection> listeners = Collections - .synchronizedCollection(new LinkedList<>()); + .synchronizedCollection(new LinkedList<>()); private Collection myListeners = null; diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringConcat.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringConcat.java index f31fbca..e16533e 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringConcat.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringConcat.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.localization; public class MutableStringConcat extends MutableString { diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFormatter.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFormatter.java index fddba06..07fad9d 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFormatter.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFormatter.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.localization; import java.util.IllegalFormatException; diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFunc.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFunc.java index d945618..82ae330 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFunc.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFunc.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.localization; import java.util.function.Function; diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringLocalized.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringLocalized.java index 583d9e5..32a6d68 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringLocalized.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringLocalized.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.localization; public class MutableStringLocalized extends MutableString { diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringParented.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringParented.java index d7b0fae..fd6c8fd 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringParented.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringParented.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.localization; public abstract class MutableStringParented extends MutableString { diff --git a/src/main/java/ru/windcorp/progressia/client/localization/Parser.java b/src/main/java/ru/windcorp/progressia/client/localization/Parser.java index 7d587dc..cdb220a 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/Parser.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/Parser.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.localization; import ru.windcorp.jputil.chars.EscapeException; @@ -30,8 +30,7 @@ import java.util.Map; public class Parser { private String filePath; - static private final Escaper ESCAPER = new Escaper.EscaperBuilder() - .withChars("n", "\n").build(); + static private final Escaper ESCAPER = new Escaper.EscaperBuilder().withChars("n", "\n").build(); public Parser(String filePath) { this.filePath = filePath; @@ -43,11 +42,7 @@ public class Parser { public Map parse() { Map parsedData = new HashMap<>(); - try ( - Reader rawData = ResourceManager - .getResource(filePath) - .getReader() - ) { + try (Reader rawData = ResourceManager.getResource(filePath).getReader()) { int code; char c; StringBuilder stringBuilder = new StringBuilder(); @@ -88,10 +83,7 @@ public class Parser { stringBuilder.append(c); } } - parsedData.put( - ESCAPER.unescape(key), - ESCAPER.unescape(stringBuilder.toString()) - ); + parsedData.put(ESCAPER.unescape(key), ESCAPER.unescape(stringBuilder.toString())); stringBuilder.setLength(0); } } else if (c == '\n') { diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index 21f6098..41aa933 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -27,25 +27,29 @@ import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.block.BlockRenderRegistry; import ru.windcorp.progressia.client.world.tile.TileRender; +import ru.windcorp.progressia.client.world.tile.TileRenderReference; import ru.windcorp.progressia.client.world.tile.TileRenderRegistry; import ru.windcorp.progressia.client.world.tile.TileRenderStack; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericChunk; -import ru.windcorp.progressia.common.world.tile.TileDataStack; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class ChunkRender - implements GenericChunk { + implements ChunkGenericRO { private final WorldRender world; - private final ChunkData data; + private final DefaultChunkData data; private final ChunkRenderModel model; private final Map tileRenderLists = Collections .synchronizedMap(new WeakHashMap<>()); - public ChunkRender(WorldRender world, ChunkData data) { + public ChunkRender(WorldRender world, DefaultChunkData data) { this.world = world; this.data = data; this.model = new ChunkRenderModel(this); @@ -55,6 +59,11 @@ public class ChunkRender public Vec3i getPosition() { return getData().getPosition(); } + + @Override + public AbsFace getUp() { + return getData().getUp(); + } @Override public BlockRender getBlock(Vec3i posInChunk) { @@ -84,11 +93,11 @@ public class ChunkRender return world; } - public ChunkData getData() { + public DefaultChunkData getData() { return data; } - public synchronized void markForUpdate() { + public void markForUpdate() { getWorld().markChunkForUpdate(getPosition()); } @@ -101,6 +110,28 @@ public class ChunkRender } private class TileRenderStackImpl extends TileRenderStack { + private class TileRenderReferenceImpl implements TileRenderReference { + private final TileDataReference parent; + + public TileRenderReferenceImpl(TileDataReference parent) { + this.parent = parent; + } + + @Override + public TileRender get() { + return TileRenderRegistry.getInstance().get(parent.get().getId()); + } + + @Override + public int getIndex() { + return parent.getIndex(); + } + + @Override + public TileRenderStack getStack() { + return TileRenderStackImpl.this; + } + } private final TileDataStack parent; @@ -119,9 +150,24 @@ public class ChunkRender } @Override - public BlockFace getFace() { + public RelFace getFace() { return parent.getFace(); } + + @Override + public TileRenderReference getReference(int index) { + return new TileRenderReferenceImpl(parent.getReference(index)); + } + + @Override + public int getIndexByTag(int tag) { + return parent.getIndexByTag(tag); + } + + @Override + public int getTagByIndex(int index) { + return parent.getTagByIndex(index); + } @Override public TileRender get(int index) { diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java index 9653abe..cd8a1d8 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java @@ -35,8 +35,10 @@ import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerRegistry; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderNone; import ru.windcorp.progressia.client.world.tile.TileRenderStack; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.common.world.rels.AxisRotations; +import ru.windcorp.progressia.common.world.rels.RelFace; public class ChunkRenderModel implements Renderable { @@ -53,11 +55,15 @@ public class ChunkRenderModel implements Renderable { public void render(ShapeRenderHelper renderer) { if (model == null) return; + float offset = DefaultChunkData.BLOCKS_PER_CHUNK / 2 - 0.5f; + renderer.pushTransform().translate( - chunk.getX() * ChunkData.BLOCKS_PER_CHUNK, - chunk.getY() * ChunkData.BLOCKS_PER_CHUNK, - chunk.getZ() * ChunkData.BLOCKS_PER_CHUNK - ); + chunk.getX() * DefaultChunkData.BLOCKS_PER_CHUNK, + chunk.getY() * DefaultChunkData.BLOCKS_PER_CHUNK, + chunk.getZ() * DefaultChunkData.BLOCKS_PER_CHUNK + ).translate(offset, offset, offset) + .mul(AxisRotations.getResolutionMatrix4(chunk.getUp())) + .translate(-offset, -offset, -offset); model.render(renderer); @@ -71,8 +77,8 @@ public class ChunkRenderModel implements Renderable { optimizers.forEach(ChunkRenderOptimizer::startRender); - chunk.forEachBiC(blockInChunk -> { - processBlockAndTiles(blockInChunk, sink); + GenericChunks.forEachBiC(relBlockInChunk -> { + processBlockAndTiles(relBlockInChunk, sink); }); for (ChunkRenderOptimizer optimizer : optimizers) { @@ -96,16 +102,16 @@ public class ChunkRenderModel implements Renderable { } } - private void processBlockAndTiles(Vec3i blockInChunk, Builder sink) { - processBlock(blockInChunk, sink); + private void processBlockAndTiles(Vec3i relBlockInChunk, Builder sink) { + processBlock(relBlockInChunk, sink); - for (BlockFace face : BlockFace.getFaces()) { - processTileStack(blockInChunk, face, sink); + for (RelFace face : RelFace.getFaces()) { + processTileStack(relBlockInChunk, face, sink); } } - private void processBlock(Vec3i blockInChunk, Builder sink) { - BlockRender block = chunk.getBlock(blockInChunk); + private void processBlock(Vec3i relBlockInChunk, Builder sink) { + BlockRender block = chunk.getBlockRel(relBlockInChunk); if (block instanceof BlockRenderNone) { return; @@ -113,48 +119,48 @@ public class ChunkRenderModel implements Renderable { if (block.needsOwnRenderable()) { sink.addPart( - block.createRenderable(chunk.getData(), blockInChunk), - new Mat4().identity().translate(blockInChunk.x, blockInChunk.y, blockInChunk.z) + block.createRenderable(chunk.getData(), relBlockInChunk), + new Mat4().identity().translate(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z) ); } - processBlockWithCROs(block, blockInChunk); + processBlockWithCROs(block, relBlockInChunk); } - private void processBlockWithCROs(BlockRender block, Vec3i blockInChunk) { + private void processBlockWithCROs(BlockRender block, Vec3i relBlockInChunk) { for (ChunkRenderOptimizer optimizer : optimizers) { - optimizer.addBlock(block, blockInChunk); + optimizer.addBlock(block, relBlockInChunk); } } - private void processTileStack(Vec3i blockInChunk, BlockFace face, Builder sink) { - TileRenderStack trs = chunk.getTilesOrNull(blockInChunk, face); + private void processTileStack(Vec3i relBlockInChunk, RelFace face, Builder sink) { + TileRenderStack trs = chunk.getTilesOrNullRel(relBlockInChunk, face); if (trs == null || trs.isEmpty()) { return; } - trs.forEach(tile -> processTile(tile, blockInChunk, face, sink)); + trs.forEach(tile -> processTile(tile, relBlockInChunk, face, sink)); } - private void processTile(TileRender tile, Vec3i blockInChunk, BlockFace face, Builder sink) { + private void processTile(TileRender tile, Vec3i relBlockInChunk, RelFace face, Builder sink) { if (tile instanceof TileRenderNone) { return; } if (tile.needsOwnRenderable()) { sink.addPart( - tile.createRenderable(chunk.getData(), blockInChunk, face), - new Mat4().identity().translate(blockInChunk.x, blockInChunk.y, blockInChunk.z) + tile.createRenderable(chunk.getData(), relBlockInChunk, face), + new Mat4().identity().translate(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z) ); } - processTileWithCROs(tile, blockInChunk, face); + processTileWithCROs(tile, relBlockInChunk, face); } - private void processTileWithCROs(TileRender tile, Vec3i blockInChunk, BlockFace face) { + private void processTileWithCROs(TileRender tile, Vec3i relBlockInChunk, RelFace face) { for (ChunkRenderOptimizer optimizer : optimizers) { - optimizer.addTile(tile, blockInChunk, face); + optimizer.addTile(tile, relBlockInChunk, face); } } diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java index c348498..1e854f2 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java @@ -21,10 +21,11 @@ package ru.windcorp.progressia.client.world; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; class ChunkUpdateListener implements ChunkDataListener { @@ -36,14 +37,14 @@ class ChunkUpdateListener implements ChunkDataListener { } @Override - public void onChunkChanged(ChunkData chunk) { + public void onChunkChanged(DefaultChunkData chunk) { world.getChunk(chunk).markForUpdate(); } @Override - public void onChunkLoaded(ChunkData chunk) { + public void onChunkLoaded(DefaultChunkData chunk) { Vec3i cursor = new Vec3i(); - for (BlockFace face : BlockFace.getFaces()) { + for (AbsFace face : AbsFace.getFaces()) { cursor.set(chunk.getX(), chunk.getY(), chunk.getZ()); cursor.add(face.getVector()); world.markChunkForUpdate(cursor); @@ -51,22 +52,22 @@ class ChunkUpdateListener implements ChunkDataListener { } @Override - public void onChunkBlockChanged(ChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current) { + public void onChunkBlockChanged(DefaultChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current) { onLocationChanged(chunk, blockInChunk); } @Override public void onChunkTilesChanged( - ChunkData chunk, + DefaultChunkData chunk, Vec3i blockInChunk, - BlockFace face, + RelFace face, TileData tile, boolean wasAdded ) { onLocationChanged(chunk, blockInChunk); } - private void onLocationChanged(ChunkData chunk, Vec3i blockInChunk) { + private void onLocationChanged(DefaultChunkData chunk, Vec3i blockInChunk) { Vec3i chunkPos = Vectors.grab3i().set(chunk.getX(), chunk.getY(), chunk.getZ()); checkCoordinate(blockInChunk, chunkPos, VectorUtil.Axis.X); @@ -82,7 +83,7 @@ class ChunkUpdateListener implements ChunkDataListener { if (block == 0) { diff = -1; - } else if (block == ChunkData.BLOCKS_PER_CHUNK - 1) { + } else if (block == DefaultChunkData.BLOCKS_PER_CHUNK - 1) { diff = +1; } else { return; diff --git a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java index 8be08c2..2ab9e7d 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java @@ -34,57 +34,58 @@ import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry; import ru.windcorp.progressia.client.world.entity.EntityRenderable; import ru.windcorp.progressia.client.world.tile.TileRender; +import ru.windcorp.progressia.client.world.tile.TileRenderReference; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.ChunkDataListeners; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.WorldDataListener; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.ChunkSet; import ru.windcorp.progressia.common.world.generic.ChunkSets; -import ru.windcorp.progressia.common.world.generic.GenericWorld; +import ru.windcorp.progressia.common.world.generic.WorldGenericRO; public class WorldRender - implements GenericWorld { + implements WorldGenericRO { - private final WorldData data; + private final DefaultWorldData data; private final Client client; - private final Map chunks = Collections.synchronizedMap(new HashMap<>()); + private final Map chunks = Collections.synchronizedMap(new HashMap<>()); private final Map entityModels = Collections.synchronizedMap(new WeakHashMap<>()); private final ChunkSet chunksToUpdate = ChunkSets.newSyncHashSet(); - public WorldRender(WorldData data, Client client) { + public WorldRender(DefaultWorldData data, Client client) { this.data = data; this.client = client; data.addListener(ChunkDataListeners.createAdder(new ChunkUpdateListener(this))); data.addListener(new WorldDataListener() { @Override - public void onChunkLoaded(WorldData world, ChunkData chunk) { + public void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { addChunk(chunk); } @Override - public void beforeChunkUnloaded(WorldData world, ChunkData chunk) { + public void beforeChunkUnloaded(DefaultWorldData world, DefaultChunkData chunk) { removeChunk(chunk); } }); } - protected void addChunk(ChunkData chunk) { + protected void addChunk(DefaultChunkData chunk) { chunks.put(chunk, new ChunkRender(WorldRender.this, chunk)); markChunkForUpdate(chunk.getPosition()); } - protected void removeChunk(ChunkData chunk) { + protected void removeChunk(DefaultChunkData chunk) { chunks.remove(chunk); } - public WorldData getData() { + public DefaultWorldData getData() { return data; } @@ -92,7 +93,7 @@ public class WorldRender return client; } - public ChunkRender getChunk(ChunkData chunkData) { + public ChunkRender getChunk(DefaultChunkData chunkData) { return chunks.get(chunkData); } @@ -110,6 +111,13 @@ public class WorldRender public Collection getEntities() { return entityModels.values(); } + + @Override + public EntityRenderable getEntity(long entityId) { + EntityData entityData = getData().getEntity(entityId); + if (entityData == null) return null; + return getEntityRenderable(entityData); + } public void render(ShapeRenderHelper renderer) { updateChunks(); diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java index d350fa8..6adbfde 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java @@ -18,26 +18,19 @@ package ru.windcorp.progressia.client.world.block; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.generic.BlockGeneric; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.Renderable; -public abstract class BlockRender extends Namespaced implements GenericBlock { +public abstract class BlockRender extends Namespaced implements BlockGeneric { public BlockRender(String id) { super(id); } - public void render(ShapeRenderHelper renderer) { - throw new UnsupportedOperationException( - "BlockRender.render() not implemented in " + this - ); - } - - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i relBlockInChunk) { return null; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java index 84a2c4b..7e60358 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java @@ -15,13 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.block; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.EmptyModel; import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; public class BlockRenderNone extends BlockRender { @@ -30,7 +30,7 @@ public class BlockRenderNone extends BlockRender { } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk) { return EmptyModel.getInstance(); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java index e4d8723..01a6011 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.block; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { @@ -29,8 +29,8 @@ public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { Texture bottomTexture, Texture northTexture, Texture southTexture, - Texture eastTexture, - Texture westTexture + Texture westTexture, + Texture eastTexture ) { super( id, @@ -38,8 +38,8 @@ public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { bottomTexture, northTexture, southTexture, - eastTexture, - westTexture + westTexture, + eastTexture ); } @@ -54,9 +54,21 @@ public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { texture ); } + + public BlockRenderOpaqueCube(String id, Texture topTexture, Texture bottomTexture, Texture sideTexture) { + this( + id, + topTexture, + bottomTexture, + sideTexture, + sideTexture, + sideTexture, + sideTexture + ); + } @Override - public boolean isOpaque(BlockFace face) { + public boolean isOpaque(RelFace face) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderRegistry.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderRegistry.java index 29bac40..2caacba 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderRegistry.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.block; import ru.windcorp.progressia.client.graphics.texture.Atlases; @@ -37,11 +37,7 @@ public class BlockRenderRegistry extends NamespacedInstanceRegistry public static Texture getBlockTexture(String name) { return new SimpleTexture( - Atlases.getSprite( - ResourceManager.getTextureResource("blocks/" + name), - BLOCKS_ATLAS_GROUP - ) - ); + Atlases.getSprite(ResourceManager.getTextureResource("blocks/" + name), BLOCKS_ATLAS_GROUP)); } public static AtlasGroup getBlocksAtlasGroup() { diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java index 1042a46..91d05e1 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java @@ -18,9 +18,8 @@ package ru.windcorp.progressia.client.world.block; -import static ru.windcorp.progressia.common.world.block.BlockFace.*; +import static ru.windcorp.progressia.common.world.rels.AbsFace.*; -import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -29,22 +28,23 @@ import glm.vec._3.i.Vec3i; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.ShapePart; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.BlockOptimizedSurface; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public abstract class BlockRenderTexturedCube extends BlockRender implements BlockOptimizedSurface { - private final Map textures = new HashMap<>(); + private final Map textures; public BlockRenderTexturedCube( String id, @@ -52,65 +52,59 @@ public abstract class BlockRenderTexturedCube Texture bottomTexture, Texture northTexture, Texture southTexture, - Texture eastTexture, - Texture westTexture + Texture westTexture, + Texture eastTexture ) { super(id); - - textures.put(TOP, topTexture); - textures.put(BOTTOM, bottomTexture); - textures.put(NORTH, northTexture); - textures.put(SOUTH, southTexture); - textures.put(EAST, eastTexture); - textures.put(WEST, westTexture); + this.textures = RelFace.mapToFaces(topTexture, bottomTexture, northTexture, southTexture, westTexture, eastTexture); } - public Texture getTexture(BlockFace blockFace) { + public Texture getTexture(RelFace blockFace) { return textures.get(blockFace); } - public Vec4 getColorMultiplier(BlockFace blockFace) { + public Vec4 getColorMultiplier(RelFace blockFace) { return Colors.WHITE; } @Override - public final void getFaces( - ChunkData chunk, Vec3i blockInChunk, BlockFace blockFace, + public final void getShapeParts( + DefaultChunkData chunk, Vec3i blockInChunk, RelFace blockFace, boolean inner, - Consumer output, + Consumer output, Vec3 offset ) { output.accept(createFace(chunk, blockInChunk, blockFace, inner, offset)); } - private Face createFace( - ChunkData chunk, Vec3i blockInChunk, BlockFace blockFace, + private ShapePart createFace( + DefaultChunkData chunk, Vec3i blockInChunk, RelFace blockFace, boolean inner, Vec3 offset ) { - return Faces.createBlockFace( + return ShapeParts.createBlockFace( WorldRenderProgram.getDefault(), getTexture(blockFace), getColorMultiplier(blockFace), offset, - blockFace, + blockFace.resolve(AbsFace.POS_Z), inner ); } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk) { boolean opaque = isBlockOpaque(); - Face[] faces = new Face[BLOCK_FACE_COUNT + (opaque ? BLOCK_FACE_COUNT : 0)]; + ShapePart[] faces = new ShapePart[BLOCK_FACE_COUNT + (opaque ? BLOCK_FACE_COUNT : 0)]; for (int i = 0; i < BLOCK_FACE_COUNT; ++i) { - faces[i] = createFace(chunk, blockInChunk, BlockFace.getFaces().get(i), false, Vectors.ZERO_3); + faces[i] = createFace(chunk, blockInChunk, RelFace.getFaces().get(i), false, Vectors.ZERO_3); } if (!opaque) { for (int i = 0; i < BLOCK_FACE_COUNT; ++i) { - faces[i + BLOCK_FACE_COUNT] = createFace(chunk, blockInChunk, BlockFace.getFaces().get(i), true, Vectors.ZERO_3); + faces[i + BLOCK_FACE_COUNT] = createFace(chunk, blockInChunk, RelFace.getFaces().get(i), true, Vectors.ZERO_3); } } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java index 7f3df03..f9801ca 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.block; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class BlockRenderTransparentCube extends BlockRenderTexturedCube { @@ -29,8 +29,8 @@ public class BlockRenderTransparentCube extends BlockRenderTexturedCube { Texture bottomTexture, Texture northTexture, Texture southTexture, - Texture eastTexture, - Texture westTexture + Texture westTexture, + Texture eastTexture ) { super( id, @@ -38,8 +38,8 @@ public class BlockRenderTransparentCube extends BlockRenderTexturedCube { bottomTexture, northTexture, southTexture, - eastTexture, - westTexture + westTexture, + eastTexture ); } @@ -54,9 +54,21 @@ public class BlockRenderTransparentCube extends BlockRenderTexturedCube { texture ); } + + public BlockRenderTransparentCube(String id, Texture topTexture, Texture bottomTexture, Texture sideTexture) { + this( + id, + topTexture, + bottomTexture, + sideTexture, + sideTexture, + sideTexture, + sideTexture + ); + } @Override - public boolean isOpaque(BlockFace face) { + public boolean isOpaque(RelFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java index b684c6a..12396dc 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java @@ -24,7 +24,7 @@ import ru.windcorp.progressia.client.world.ChunkRender; import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; /** * Chunk render optimizer (CRO) is an object that produces optimized models for @@ -35,6 +35,12 @@ import ru.windcorp.progressia.common.world.block.BlockFace; * tiles. An example of a CRO is {@link ChunkRenderOptimizerSurface}: it removes * block surfaces and tiles that it knows cannot be seen, thus significantly * reducing total polygon count. + *

+ * As with everything related to rendering chunks, CROs are interacted with + * using the relative local chunk coordinate system. In this coordinate system, + * the coordinates are the chunk coordinates relativized using the chunks's up + * direction. In simpler terms, coordinates are {@code [0; BLOCKS_PER_CHUNK)} + * and Z is always up. *

CRO lifecycle

* A CRO instance is created by {@link ChunkRenderOptimizerRegistry}. It may * then be used to work on multiple chunks sequentially. Each chunk is processed @@ -44,7 +50,7 @@ import ru.windcorp.progressia.common.world.block.BlockFace; * instance. *
  • {@link #startRender()} is invoked. The CRO must reset its state.
  • *
  • {@link #addBlock(BlockRender, Vec3i)} and - * {@link #addTile(TileRender, Vec3i, BlockFace)} are invoked for each block and + * {@link #addTile(TileRender, Vec3i, RelFace)} are invoked for each block and * tile that this CRO should optimize. {@code addTile} specifies tiles in order * of ascension within a tile stack.
  • *
  • {@link #endRender()} is invoked. The CRO may perform any pending @@ -98,12 +104,13 @@ public abstract class ChunkRenderOptimizer extends Namespaced { * method is only invoked once per block. This method is not necessarily * invoked for each block. * - * @param block a {@link BlockRender} instance describing the block. - * It corresponds to - * {@code getChunk().getBlock(blockInChunk)}. - * @param blockInChunk the position of the block + * @param block a {@link BlockRender} instance describing the + * block. + * It corresponds to + * {@code getChunk().getBlock(blockInChunk)}. + * @param relBlockInChunk the relative position of the block */ - public abstract void addBlock(BlockRender block, Vec3i blockInChunk); + public abstract void addBlock(BlockRender block, Vec3i relBlockInChunk); /** * Requests that this CRO processes the provided tile. This method may only @@ -112,11 +119,12 @@ public abstract class ChunkRenderOptimizer extends Namespaced { * invoked for each tile. When multiple tiles in a tile stack are requested, * this method is invoked for lower tiles first. * - * @param tile a {@link BlockRender} instance describing the tile - * @param blockInChunk the position of the block that the tile belongs to - * @param blockFace the face that the tile belongs to + * @param tile a {@link BlockRender} instance describing the tile + * @param relBlockInChunk the relative position of the block that the tile + * belongs to + * @param blockFace the face that the tile belongs to */ - public abstract void addTile(TileRender tile, Vec3i blockInChunk, BlockFace blockFace); + public abstract void addTile(TileRender tile, Vec3i relBlockInChunk, RelFace blockFace); /** * Requests that the CRO assembles and outputs its model. This method may diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerRegistry.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerRegistry.java index 7e4dc87..7676b4f 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerRegistry.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerRegistry.java @@ -15,15 +15,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.cro; import ru.windcorp.progressia.common.util.namespaces.NamespacedFactoryRegistry; public class ChunkRenderOptimizerRegistry extends NamespacedFactoryRegistry { - + private static final ChunkRenderOptimizerRegistry INSTANCE = new ChunkRenderOptimizerRegistry(); - + /** * @return the instance */ diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java index 488938e..296e7b8 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java @@ -18,9 +18,9 @@ package ru.windcorp.progressia.client.world.cro; -import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; -import static ru.windcorp.progressia.common.world.block.BlockFace.BLOCK_FACE_COUNT; -import static ru.windcorp.progressia.common.world.generic.GenericTileStack.TILES_PER_FACE; +import static ru.windcorp.progressia.common.world.DefaultChunkData.BLOCKS_PER_CHUNK; +import static ru.windcorp.progressia.common.world.generic.TileGenericStackRO.TILES_PER_FACE; +import static ru.windcorp.progressia.common.world.rels.AbsFace.BLOCK_FACE_COUNT; import java.util.ArrayList; import java.util.Collection; @@ -29,7 +29,7 @@ import java.util.function.Consumer; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; +import ru.windcorp.progressia.client.graphics.model.ShapePart; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; @@ -37,8 +37,9 @@ import ru.windcorp.progressia.client.world.ChunkRender; import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.common.world.rels.RelFace; public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { @@ -52,39 +53,42 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { private static interface OptimizedSurface { /** - * Creates and outputs a set of faces that correspond to this surface. - * The coordinates of the face vertices must be in chunk coordinate - * system. + * Creates and outputs a set of shape parts that correspond to this + * surface. The coordinates of the face vertices must be in chunk + * coordinate system. * - * @param chunk the chunk that contains the requested face - * @param blockInChunk the block in chunk - * @param blockFace the requested face - * @param inner whether this face should be visible from inside - * ({@code true}) or outside ({@code false}) - * @param output a consumer that the created faces must be given - * to - * @param offset an additional offset that must be applied to all - * vertices + * @param chunk the chunk that contains the requested face + * @param relBlockInChunk the relative block in chunk + * @param blockFace the requested face + * @param inner whether this face should be visible from + * inside + * ({@code true}) or outside ({@code false}) + * @param output a consumer that the created shape parts must + * be + * given to + * @param offset an additional offset that must be applied to + * all + * vertices */ - void getFaces( - ChunkData chunk, - Vec3i blockInChunk, - BlockFace blockFace, + void getShapeParts( + DefaultChunkData chunk, + Vec3i relBlockInChunk, + RelFace blockFace, boolean inner, - Consumer output, + Consumer output, Vec3 offset /* kostyl 156% */ ); /** * Returns the opacity of the surface identified by the provided - * {@link BlockFace}. + * {@link RelFace}. * Opaque surfaces prevent surfaces behind them from being included in * chunk models. * * @param blockFace the face to query * @return {@code true} iff the surface is opaque. */ - boolean isOpaque(BlockFace blockFace); + boolean isOpaque(RelFace blockFace); } /** @@ -159,29 +163,29 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } @Override - public void addBlock(BlockRender block, Vec3i pos) { + public void addBlock(BlockRender block, Vec3i relBlockInChunk) { if (!(block instanceof BlockOptimizedSurface)) return; BlockOptimizedSurface bos = (BlockOptimizedSurface) block; - addBlock(pos, bos); + addBlock(relBlockInChunk, bos); } @Override - public void addTile(TileRender tile, Vec3i pos, BlockFace face) { + public void addTile(TileRender tile, Vec3i relBlockInChunk, RelFace face) { if (!(tile instanceof TileOptimizedSurface)) return; TileOptimizedSurface tos = (TileOptimizedSurface) tile; - addTile(pos, face, tos); + addTile(relBlockInChunk, face, tos); } - protected void addBlock(Vec3i pos, BlockOptimizedSurface block) { - getBlock(pos).block = block; + private void addBlock(Vec3i relBlockInChunk, BlockOptimizedSurface block) { + getBlock(relBlockInChunk).block = block; } - private void addTile(Vec3i pos, BlockFace face, TileOptimizedSurface tile) { - FaceInfo faceInfo = getFace(pos, face); + private void addTile(Vec3i relBlockInChunk, RelFace face, TileOptimizedSurface tile) { + FaceInfo faceInfo = getFace(relBlockInChunk, face); int index = faceInfo.tileCount; faceInfo.tileCount++; @@ -197,63 +201,58 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } } - protected BlockInfo getBlock(Vec3i cursor) { - return data[cursor.x][cursor.y][cursor.z]; + protected BlockInfo getBlock(Vec3i relBlockInChunk) { + return data[relBlockInChunk.x][relBlockInChunk.y][relBlockInChunk.z]; } - protected FaceInfo getFace(Vec3i cursor, BlockFace face) { - return getBlock(cursor).faces[face.getId()]; + protected FaceInfo getFace(Vec3i relBlockInChunk, RelFace face) { + return getBlock(relBlockInChunk).faces[face.getId()]; } @Override public Renderable endRender() { - Collection shapeFaces = new ArrayList<>( + Collection shapeParts = new ArrayList<>( BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3 ); - Vec3i cursor = new Vec3i(); - Consumer consumer = shapeFaces::add; + Consumer consumer = shapeParts::add; - for (cursor.x = 0; cursor.x < BLOCKS_PER_CHUNK; ++cursor.x) { - for (cursor.y = 0; cursor.y < BLOCKS_PER_CHUNK; ++cursor.y) { - for (cursor.z = 0; cursor.z < BLOCKS_PER_CHUNK; ++cursor.z) { - processInnerFaces(cursor, consumer); - processOuterFaces(cursor, consumer); - } - } - } + GenericChunks.forEachBiC(relBlockInChunk -> { + processInnerFaces(relBlockInChunk, consumer); + processOuterFaces(relBlockInChunk, consumer); + }); - if (shapeFaces.isEmpty()) { + if (shapeParts.isEmpty()) { return null; } return new Shape( Usage.STATIC, WorldRenderProgram.getDefault(), - shapeFaces.toArray(new Face[shapeFaces.size()]) + shapeParts.toArray(new ShapePart[shapeParts.size()]) ); } private void processOuterFaces( - Vec3i blockInChunk, - Consumer output + Vec3i relBlockInChunk, + Consumer output ) { - for (BlockFace blockFace : BlockFace.getFaces()) { - processOuterFace(blockInChunk, blockFace, output); + for (RelFace blockFace : RelFace.getFaces()) { + processOuterFace(relBlockInChunk, blockFace, output); } } - private void processOuterFace(Vec3i blockInChunk, BlockFace blockFace, Consumer output) { - if (!shouldRenderOuterFace(blockInChunk, blockFace)) + private void processOuterFace(Vec3i relBlockInChunk, RelFace blockFace, Consumer output) { + if (!shouldRenderOuterFace(relBlockInChunk, blockFace)) return; - FaceInfo info = getFace(blockInChunk, blockFace); + FaceInfo info = getFace(relBlockInChunk, blockFace); if (info.tileCount == 0 && info.block.block == null) return; - Vec3 faceOrigin = new Vec3(blockInChunk.x, blockInChunk.y, blockInChunk.z); - Vec3 offset = new Vec3(blockFace.getFloatVector()).mul(OVERLAY_OFFSET); + Vec3 faceOrigin = new Vec3(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z); + Vec3 offset = new Vec3(blockFace.getRelFloatVector()).mul(OVERLAY_OFFSET); for ( int layer = info.topOpaqueSurface; @@ -264,32 +263,29 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { if (surface == null) continue; // layer may be BLOCK_LAYER, then block may be null - surface.getFaces(chunk.getData(), blockInChunk, blockFace, false, output, faceOrigin); + surface.getShapeParts(chunk.getData(), relBlockInChunk, blockFace, false, output, faceOrigin); faceOrigin.add(offset); } } - private void processInnerFaces( - Vec3i blockInChunk, - Consumer output - ) { - for (BlockFace blockFace : BlockFace.getFaces()) { - processInnerFace(blockInChunk, blockFace, output); + private void processInnerFaces(Vec3i relBlockInChunk, Consumer output) { + for (RelFace blockFace : RelFace.getFaces()) { + processInnerFace(relBlockInChunk, blockFace, output); } } - private void processInnerFace(Vec3i blockInChunk, BlockFace blockFace, Consumer output) { - if (!shouldRenderInnerFace(blockInChunk, blockFace)) + private void processInnerFace(Vec3i relBlockInChunk, RelFace blockFace, Consumer output) { + if (!shouldRenderInnerFace(relBlockInChunk, blockFace)) return; - FaceInfo info = getFace(blockInChunk, blockFace); + FaceInfo info = getFace(relBlockInChunk, blockFace); if (info.tileCount == 0 && info.block.block == null) return; - Vec3 faceOrigin = new Vec3(blockInChunk.x, blockInChunk.y, blockInChunk.z); - Vec3 offset = new Vec3(blockFace.getFloatVector()).mul(OVERLAY_OFFSET); + Vec3 faceOrigin = new Vec3(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z); + Vec3 offset = new Vec3(blockFace.getRelFloatVector()).mul(OVERLAY_OFFSET); for ( int layer = FaceInfo.BLOCK_LAYER; @@ -300,35 +296,35 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { if (surface == null) continue; // layer may be BLOCK_LAYER, then block may be null - surface.getFaces(chunk.getData(), blockInChunk, blockFace, true, output, faceOrigin); + surface.getShapeParts(chunk.getData(), relBlockInChunk, blockFace, true, output, faceOrigin); faceOrigin.add(offset); } } - private boolean shouldRenderOuterFace(Vec3i blockInChunk, BlockFace face) { - blockInChunk.add(face.getVector()); + private boolean shouldRenderOuterFace(Vec3i relBlockInChunk, RelFace face) { + relBlockInChunk.add(face.getRelVector()); try { - return shouldRenderWhenFacing(blockInChunk, face); + return shouldRenderWhenFacing(relBlockInChunk, face); } finally { - blockInChunk.sub(face.getVector()); + relBlockInChunk.sub(face.getRelVector()); } } - private boolean shouldRenderInnerFace(Vec3i blockInChunk, BlockFace face) { - return shouldRenderWhenFacing(blockInChunk, face); + private boolean shouldRenderInnerFace(Vec3i relBlockInChunk, RelFace face) { + return shouldRenderWhenFacing(relBlockInChunk, face); } - private boolean shouldRenderWhenFacing(Vec3i blockInChunk, BlockFace face) { - if (chunk.containsBiC(blockInChunk)) { - return shouldRenderWhenFacingLocal(blockInChunk, face); + private boolean shouldRenderWhenFacing(Vec3i relBlockInChunk, RelFace face) { + if (GenericChunks.containsBiC(relBlockInChunk)) { + return shouldRenderWhenFacingLocal(relBlockInChunk, face); } else { - return shouldRenderWhenFacingNeighbor(blockInChunk, face); + return shouldRenderWhenFacingNeighbor(relBlockInChunk, face); } } - private boolean shouldRenderWhenFacingLocal(Vec3i blockInChunk, BlockFace face) { - BlockOptimizedSurface block = getBlock(blockInChunk).block; + private boolean shouldRenderWhenFacingLocal(Vec3i relBlockInChunk, RelFace face) { + BlockOptimizedSurface block = getBlock(relBlockInChunk).block; if (block == null) { return true; @@ -340,36 +336,37 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { return true; } - private boolean shouldRenderWhenFacingNeighbor(Vec3i blockInLocalChunk, BlockFace face) { - Vec3i blockInChunk = Vectors.grab3i().set(blockInLocalChunk.x, blockInLocalChunk.y, blockInLocalChunk.z); + private boolean shouldRenderWhenFacingNeighbor(Vec3i relBlockInLocalChunk, RelFace face) { + Vec3i blockInChunk = Vectors.grab3i(); + chunk.resolve(relBlockInLocalChunk, blockInChunk); Vec3i chunkPos = Vectors.grab3i().set(chunk.getX(), chunk.getY(), chunk.getZ()); try { // Determine blockInChunk and chunkPos - if (blockInLocalChunk.x == -1) { + if (blockInChunk.x == -1) { blockInChunk.x = BLOCKS_PER_CHUNK - 1; chunkPos.x -= 1; - } else if (blockInLocalChunk.x == BLOCKS_PER_CHUNK) { + } else if (blockInChunk.x == BLOCKS_PER_CHUNK) { blockInChunk.x = 0; chunkPos.x += 1; - } else if (blockInLocalChunk.y == -1) { + } else if (blockInChunk.y == -1) { blockInChunk.y = BLOCKS_PER_CHUNK - 1; chunkPos.y -= 1; - } else if (blockInLocalChunk.y == BLOCKS_PER_CHUNK) { + } else if (blockInChunk.y == BLOCKS_PER_CHUNK) { blockInChunk.y = 0; chunkPos.y += 1; - } else if (blockInLocalChunk.z == -1) { + } else if (blockInChunk.z == -1) { blockInChunk.z = BLOCKS_PER_CHUNK - 1; chunkPos.z -= 1; - } else if (blockInLocalChunk.z == BLOCKS_PER_CHUNK) { + } else if (blockInChunk.z == BLOCKS_PER_CHUNK) { blockInChunk.z = 0; chunkPos.z += 1; } else { throw new AssertionError( "Requested incorrent neighbor (" - + blockInLocalChunk.x + "; " - + blockInLocalChunk.y + "; " - + blockInLocalChunk.z + ")" + + relBlockInLocalChunk.x + "; " + + relBlockInLocalChunk.y + "; " + + relBlockInLocalChunk.z + ")" ); } @@ -382,8 +379,11 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { return true; BlockOptimizedSurface bos = (BlockOptimizedSurface) block; - if (!bos.isOpaque(face)) + RelFace rotatedFace = face.rotate(this.chunk.getUp(), chunk.getUp()); + + if (!bos.isOpaque(rotatedFace)) { return true; + } return false; diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRender.java b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRender.java index 13a2b24..8243c9d 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRender.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.entity; import ru.windcorp.progressia.common.util.namespaces.Namespaced; diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderRegistry.java b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderRegistry.java index 60b7bf6..e6ff550 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderRegistry.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.entity; import java.io.IOException; @@ -37,14 +37,9 @@ public class EntityRenderRegistry extends NamespacedInstanceRegistry. */ - + package ru.windcorp.progressia.client.world.entity; import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.GenericEntity; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; -public abstract class EntityRenderable implements Renderable, GenericEntity { +public abstract class EntityRenderable implements Renderable, EntityGeneric { private final EntityData data; + + private long stateComputedForFrame = -1; public EntityRenderable(EntityData data) { this.data = data; } + /** + * Updates the state of this model. This method is invoked exactly once per + * renderable per frame before this entity is queried for the first time. + */ + protected void update() { + // Do nothing + } + + private void updateIfNecessary() { + if (stateComputedForFrame != GraphicsInterface.getFramesRendered()) { + update(); + stateComputedForFrame = GraphicsInterface.getFramesRendered(); + } + } + + @Override + public final void render(ShapeRenderHelper renderer) { + updateIfNecessary(); + doRender(renderer); + } + + protected abstract void doRender(ShapeRenderHelper renderer); + public EntityData getData() { return data; } @@ -44,8 +71,42 @@ public abstract class EntityRenderable implements Renderable, GenericEntity { public String getId() { return getData().getId(); } + + @Override + public long getEntityId() { + return getData().getEntityId(); + } - public void getViewPoint(Vec3 output) { + public final Vec3 getLookingAt(Vec3 output) { + if (output == null) output = new Vec3(); + updateIfNecessary(); + doGetLookingAt(output); + return output; + } + + protected void doGetLookingAt(Vec3 output) { + output.set(getData().getLookingAt()); + } + + public final Vec3 getUpVector(Vec3 output) { + if (output == null) output = new Vec3(); + updateIfNecessary(); + doGetUpVector(output); + return output; + } + + protected void doGetUpVector(Vec3 output) { + output.set(getData().getUpVector()); + } + + public final Vec3 getViewPoint(Vec3 output) { + if (output == null) output = new Vec3(); + updateIfNecessary(); + doGetViewPoint(output); + return output; + } + + protected void doGetViewPoint(Vec3 output) { output.set(0, 0, 0); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java index 1609bfc..205981e 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.entity; import static java.lang.Math.*; @@ -32,17 +32,14 @@ public class HumanoidModel extends NPedModel { protected static abstract class Limb extends BodyPart { private final float animationOffset; - public Limb( - Renderable renderable, - Vec3 joint, - float animationOffset - ) { + public Limb(Renderable renderable, Vec3 joint, float animationOffset) { super(renderable, joint); this.animationOffset = animationOffset; } @Override protected void applyTransform(Mat4 mat, NPedModel model) { + super.applyTransform(mat, model); float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset; float value = sin(phase); float amplitude = getSwingAmplitude((HumanoidModel) model) * model.getVelocityParameter(); @@ -54,11 +51,7 @@ public class HumanoidModel extends NPedModel { } public static class Leg extends Limb { - public Leg( - Renderable renderable, - Vec3 joint, - float animationOffset - ) { + public Leg(Renderable renderable, Vec3 joint, float animationOffset) { super(renderable, joint, animationOffset); } @@ -69,11 +62,7 @@ public class HumanoidModel extends NPedModel { } public static class Arm extends Limb { - public Arm( - Renderable renderable, - Vec3 joint, - float animationOffset - ) { + public Arm(Renderable renderable, Vec3 joint, float animationOffset) { super(renderable, joint, animationOffset); } @@ -91,18 +80,11 @@ public class HumanoidModel extends NPedModel { private float walkingLegSwing; private float walkingArmSwing; - public HumanoidModel( - EntityData entity, + public HumanoidModel(EntityData entity, - Body body, - Head head, - Arm leftArm, - Arm rightArm, - Leg leftLeg, - Leg rightLeg, + Body body, Head head, Arm leftArm, Arm rightArm, Leg leftLeg, Leg rightLeg, - float scale - ) { + float scale) { super(entity, body, head, scale); this.leftArm = leftArm; this.rightArm = rightArm; diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java index ead6565..12a078e 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java @@ -18,11 +18,8 @@ package ru.windcorp.progressia.client.world.entity; -import static java.lang.Math.atan2; -import static java.lang.Math.min; import static java.lang.Math.pow; import static java.lang.Math.toRadians; -import static ru.windcorp.progressia.common.util.FloatMathUtil.normalizeAngle; import glm.Glm; import glm.mat._4.Mat4; @@ -32,6 +29,9 @@ import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.common.Units; +import ru.windcorp.progressia.common.util.FloatMathUtil; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.entity.EntityData; public abstract class NPedModel extends EntityRenderable { @@ -51,29 +51,30 @@ public abstract class NPedModel extends EntityRenderable { ShapeRenderHelper renderer, NPedModel model ) { - renderer.pushTransform().translate(translation); applyTransform(renderer.pushTransform(), model); renderable.render(renderer); renderer.popTransform(); - renderer.popTransform(); } - protected abstract void applyTransform(Mat4 mat, NPedModel model); + protected void applyTransform(Mat4 mat, NPedModel model) { + mat.translate(getTranslation()); + } public Vec3 getTranslation() { return translation; } + + public Mat4 getTransform(Mat4 output, NPedModel model) { + if (output == null) output = new Mat4().identity(); + applyTransform(output, model); + return output; + } } public static class Body extends BodyPart { public Body(Renderable renderable) { super(renderable, null); } - - @Override - protected void applyTransform(Mat4 mat, NPedModel model) { - // Do nothing - } } public static class Head extends BodyPart { @@ -97,7 +98,8 @@ public abstract class NPedModel extends EntityRenderable { @Override protected void applyTransform(Mat4 mat, NPedModel model) { - mat.rotateZ(model.getHeadYaw()).rotateY(model.getHeadPitch()); + super.applyTransform(mat, model); + mat.rotateZ(-model.getHeadYaw()).rotateY(-model.getHeadPitch()); } public Vec3 getViewPoint() { @@ -105,6 +107,8 @@ public abstract class NPedModel extends EntityRenderable { } } + public static boolean flag; + protected final Body body; protected final Head head; @@ -128,7 +132,9 @@ public abstract class NPedModel extends EntityRenderable { private float walkingFrequency; - private float bodyYaw = Float.NaN; + private final Vec3 bodyLookingAt = new Vec3().set(0); + private final Mat4 bodyTransform = new Mat4(); + private float headYaw; private float headPitch; @@ -138,68 +144,121 @@ public abstract class NPedModel extends EntityRenderable { this.head = head; this.scale = scale; - evaluateAngles(); + computeRotations(); } @Override - public void render(ShapeRenderHelper renderer) { - renderer.pushTransform().scale(scale).rotateZ(bodyYaw); + protected void doRender(ShapeRenderHelper renderer) { + renderer.pushTransform().scale(scale).mul(bodyTransform); renderBodyParts(renderer); renderer.popTransform(); - - accountForVelocity(); - evaluateAngles(); } protected void renderBodyParts(ShapeRenderHelper renderer) { body.render(renderer, this); head.render(renderer, this); } - - private void evaluateAngles() { - float globalYaw = normalizeAngle(getData().getYaw()); - - if (Float.isNaN(bodyYaw)) { - bodyYaw = globalYaw; - headYaw = 0; - } else { - headYaw = normalizeAngle(globalYaw - bodyYaw); - - if (headYaw > +head.maxYaw) { - bodyYaw += headYaw - +head.maxYaw; - headYaw = +head.maxYaw; - } else if (headYaw < -head.maxYaw) { - bodyYaw += headYaw - -head.maxYaw; - headYaw = -head.maxYaw; - } - } - - bodyYaw = normalizeAngle(bodyYaw); - - headPitch = Glm.clamp( - getData().getPitch(), - -head.maxPitch, - head.maxPitch - ); + + @Override + protected void update() { + advanceTime(); + computeRotations(); } - private void accountForVelocity() { - Vec3 horizontal = new Vec3(getData().getVelocity()); - horizontal.z = 0; + private void computeRotations() { + if (!bodyLookingAt.any()) { + getData().getForwardVector(bodyLookingAt); + headYaw = 0; + } else { + ensureBodyLookingAtIsPerpendicularToUpVector(); + computeDesiredHeadYaw(); + clampHeadYawAndChangeBodyLookingAt(); + } + + recomputeBodyTransform(); + + setHeadPitch(); + } + + private void ensureBodyLookingAtIsPerpendicularToUpVector() { + Vec3 up = getData().getUpVector(); + if (up.dot(bodyLookingAt) > 1 - 1e-4) return; + + Vec3 tmp = Vectors.grab3(); + + tmp.set(up).mul(-up.dot(bodyLookingAt)).add(bodyLookingAt); + + float tmpLength = tmp.length(); + if (tmpLength > 1e-4) { + bodyLookingAt.set(tmp).div(tmpLength); + } else { + // bodyLookingAt is suddenly parallel to up vector -- PANIC! ENTERING RESCUE MODE! + getData().getForwardVector(bodyLookingAt); + } + + Vectors.release(tmp); + } + + private void computeDesiredHeadYaw() { + Vec3 newDirection = getData().getForwardVector(null); + Vec3 oldDirection = bodyLookingAt; + Vec3 up = getData().getUpVector(); + + headYaw = (float) VectorUtil.getAngle(oldDirection, newDirection, up); + } + + private void clampHeadYawAndChangeBodyLookingAt() { + float bodyYawChange = 0; + + if (headYaw > +head.maxYaw) { + bodyYawChange = headYaw - +head.maxYaw; + headYaw = +head.maxYaw; + } else if (headYaw < -head.maxYaw) { + bodyYawChange = headYaw - -head.maxYaw; + headYaw = -head.maxYaw; + } + + if (bodyYawChange != 0) { + VectorUtil.rotate(bodyLookingAt, getData().getUpVector(), bodyYawChange); + } + } + + private void recomputeBodyTransform() { + Vec3 u = getData().getUpVector(); + Vec3 f = bodyLookingAt; + Vec3 s = Vectors.grab3(); + + s.set(u).cross(f); + + bodyTransform.identity().set( + +f.x, +f.y, +f.z, 0, + -s.x, -s.y, -s.z, 0, + +u.x, +u.y, +u.z, 0, + 0, 0, 0, 1 + ); + + Vectors.release(s); + } + + private void setHeadPitch() { + headPitch = Glm.clamp((float) getData().getPitch(), -head.maxPitch, +head.maxPitch); + } + + private void advanceTime() { + Vec3 horizontal = getData().getUpVector() + .mul_(-getData().getUpVector().dot(getData().getVelocity())) + .add(getData().getVelocity()); velocity = horizontal.length(); - evaluateVelocityCoeff(); + computeVelocityParameter(); - // TODO switch to world time walkingParameter += velocity * GraphicsInterface.getFrameLength() * 1000; - - bodyYaw += velocityParameter * normalizeAngle( - (float) (atan2(horizontal.y, horizontal.x) - bodyYaw) - ) * min(1, GraphicsInterface.getFrameLength() * 10); + + rotateBodyWithMovement(horizontal); } - private void evaluateVelocityCoeff() { + private void computeVelocityParameter() { if (velocity > maxEffectiveVelocity) { velocityParameter = 1; } else { @@ -207,17 +266,39 @@ public abstract class NPedModel extends EntityRenderable { } } + private void rotateBodyWithMovement(Vec3 target) { + if (velocityParameter == 0 || !target.any() || Glm.equals(target, bodyLookingAt)) { + return; + } + + Vec3 axis = getData().getUpVector(); + + float yawDifference = FloatMathUtil.normalizeAngle( + (float) VectorUtil.getAngle( + bodyLookingAt, + target.normalize_(), + axis + ) + ); + + float bodyYawChange = + velocityParameter * + yawDifference * + (float) Math.expm1(GraphicsInterface.getFrameLength() * 10); + + VectorUtil.rotate(bodyLookingAt, axis, bodyYawChange); + } + @Override - public void getViewPoint(Vec3 output) { + protected void doGetViewPoint(Vec3 output) { Mat4 m = new Mat4(); Vec4 v = new Vec4(); m.identity() .scale(scale) - .rotateZ(bodyYaw) - .translate(head.getTranslation()) - .rotateZ(headYaw) - .rotateY(headPitch); + .mul(bodyTransform); + + head.getTransform(m, this); v.set(head.getViewPoint(), 1); m.mul(v); @@ -232,9 +313,9 @@ public abstract class NPedModel extends EntityRenderable { public Head getHead() { return head; } - - public float getBodyYaw() { - return bodyYaw; + + public Vec3 getBodyLookingAt() { + return bodyLookingAt; } public float getHeadYaw() { diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java index 8755b08..5cb335c 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.entity; import static java.lang.Math.*; @@ -33,17 +33,14 @@ public class QuadripedModel extends NPedModel { public static class Leg extends BodyPart { private final float animationOffset; - public Leg( - Renderable renderable, - Vec3 joint, - float animationOffset - ) { + public Leg(Renderable renderable, Vec3 joint, float animationOffset) { super(renderable, joint); this.animationOffset = animationOffset; } @Override protected void applyTransform(Mat4 mat, NPedModel model) { + super.applyTransform(mat, model); float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset; float value = sin(phase); float amplitude = ((QuadripedModel) model).getWalkingSwing() * model.getVelocityParameter(); @@ -57,18 +54,11 @@ public class QuadripedModel extends NPedModel { private float walkingSwing = (float) toRadians(30); - public QuadripedModel( - EntityData entity, + public QuadripedModel(EntityData entity, - Body body, - Head head, - Leg leftForeLeg, - Leg rightForeLeg, - Leg leftHindLeg, - Leg rightHindLeg, + Body body, Head head, Leg leftForeLeg, Leg rightForeLeg, Leg leftHindLeg, Leg rightHindLeg, - float scale - ) { + float scale) { super(entity, body, head, scale); this.leftForeLeg = leftForeLeg; diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java index 4f82d86..dcb6c54 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java @@ -18,28 +18,21 @@ package ru.windcorp.progressia.client.world.tile; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizer; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.generic.TileGeneric; +import ru.windcorp.progressia.common.world.rels.RelFace; -public class TileRender extends Namespaced implements GenericTile { +public class TileRender extends Namespaced implements TileGeneric { public TileRender(String id) { super(id); } - public void render(ShapeRenderHelper renderer, BlockFace face) { - throw new UnsupportedOperationException( - "TileRender.render() not implemented in " + this - ); - } - - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, BlockFace face) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk, RelFace face) { return null; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java index 8e2a6e4..2e37033 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java @@ -20,20 +20,20 @@ package ru.windcorp.progressia.client.world.tile; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.EmptyModel; import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.rels.RelFace; public class TileRenderNone extends TileRender { public TileRenderNone(String id) { super(id); } - + @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, BlockFace face) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk, RelFace face) { return EmptyModel.getInstance(); } - + @Override public boolean needsOwnRenderable() { return false; diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java index e4990e8..068bb1e 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java @@ -15,11 +15,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class TileRenderOpaqueSurface extends TileRenderSurface { @@ -28,7 +28,7 @@ public class TileRenderOpaqueSurface extends TileRenderSurface { } @Override - public boolean isOpaque(BlockFace face) { + public boolean isOpaque(RelFace face) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java new file mode 100644 index 0000000..9ec5194 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java @@ -0,0 +1,27 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.client.world.tile; + +import ru.windcorp.progressia.client.world.ChunkRender; +import ru.windcorp.progressia.client.world.block.BlockRender; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; + +public interface TileRenderReference + extends TileGenericReferenceRO { + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderRegistry.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderRegistry.java index b240933..7b9d5ec 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderRegistry.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Atlases; @@ -41,11 +41,7 @@ public class TileRenderRegistry extends NamespacedInstanceRegistry { public static Texture getTileTexture(String name) { return new SimpleTexture( - Atlases.getSprite( - ResourceManager.getTextureResource("tiles/" + name), - TILES_ATLAS_GROUP - ) - ); + Atlases.getSprite(ResourceManager.getTextureResource("tiles/" + name), TILES_ATLAS_GROUP)); } } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java index 6bb8fb0..b0c6b65 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java @@ -18,12 +18,15 @@ package ru.windcorp.progressia.client.world.tile; -import ru.windcorp.progressia.client.world.ChunkRender; -import ru.windcorp.progressia.common.world.generic.GenericTileStack; -import ru.windcorp.progressia.common.world.tile.TileDataStack; +import java.util.AbstractList; +import ru.windcorp.progressia.client.world.ChunkRender; +import ru.windcorp.progressia.client.world.block.BlockRender; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; public abstract class TileRenderStack - extends GenericTileStack { + extends AbstractList + implements TileGenericStackRO { public abstract TileDataStack getData(); diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java index eebcb07..604bf69 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java @@ -25,16 +25,17 @@ import glm.vec._3.i.Vec3i; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.ShapePart; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.TileOptimizedSurface; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public abstract class TileRenderSurface extends TileRender implements TileOptimizedSurface { @@ -49,41 +50,41 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi this(id, null); } - public Texture getTexture(BlockFace blockFace) { + public Texture getTexture(RelFace blockFace) { return texture; } - public Vec4 getColorMultiplier(BlockFace blockFace) { + public Vec4 getColorMultiplier(RelFace blockFace) { return Colors.WHITE; } @Override - public final void getFaces( - ChunkData chunk, Vec3i blockInChunk, BlockFace blockFace, + public final void getShapeParts( + DefaultChunkData chunk, Vec3i relBlockInChunk, RelFace blockFace, boolean inner, - Consumer output, + Consumer output, Vec3 offset ) { - output.accept(createFace(chunk, blockInChunk, blockFace, inner, offset)); + output.accept(createFace(chunk, relBlockInChunk, blockFace, inner, offset)); } - private Face createFace( - ChunkData chunk, Vec3i blockInChunk, BlockFace blockFace, + private ShapePart createFace( + DefaultChunkData chunk, Vec3i blockInChunk, RelFace blockFace, boolean inner, Vec3 offset ) { - return Faces.createBlockFace( + return ShapeParts.createBlockFace( WorldRenderProgram.getDefault(), getTexture(blockFace), getColorMultiplier(blockFace), offset, - blockFace, + blockFace.resolve(AbsFace.POS_Z), inner ); } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, BlockFace blockFace) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk, RelFace blockFace) { return new Shape( Usage.STATIC, WorldRenderProgram.getDefault(), diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java index b35986e..d311231 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java @@ -15,11 +15,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class TileRenderTransparentSurface extends TileRenderSurface { @@ -28,7 +28,7 @@ public class TileRenderTransparentSurface extends TileRenderSurface { } @Override - public boolean isOpaque(BlockFace face) { + public boolean isOpaque(RelFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/common/Units.java b/src/main/java/ru/windcorp/progressia/common/Units.java index 842e378..0f868aa 100644 --- a/src/main/java/ru/windcorp/progressia/common/Units.java +++ b/src/main/java/ru/windcorp/progressia/common/Units.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common; import java.lang.annotation.ElementType; @@ -112,12 +112,9 @@ public class Units { private static final TCharFloatMap PREFIXES_BY_CHAR; static { - TCharFloatMap prefixes = new TCharFloatHashMap( - gnu.trove.impl.Constants.DEFAULT_CAPACITY, - gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR, - gnu.trove.impl.Constants.DEFAULT_CHAR_NO_ENTRY_VALUE, - Float.NaN - ); + TCharFloatMap prefixes = new TCharFloatHashMap(gnu.trove.impl.Constants.DEFAULT_CAPACITY, + gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR, gnu.trove.impl.Constants.DEFAULT_CHAR_NO_ENTRY_VALUE, + Float.NaN); prefixes.put('G', 1e+9f); prefixes.put('M', 1e+6f); @@ -133,13 +130,8 @@ public class Units { private static final TObjectFloatMap KNOWN_UNITS = createMap(); private static TObjectFloatMap createMap() { - return TCollections.synchronizedMap( - new TObjectFloatHashMap<>( - gnu.trove.impl.Constants.DEFAULT_CAPACITY, - gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR, - Float.NaN - ) - ); + return TCollections.synchronizedMap(new TObjectFloatHashMap<>(gnu.trove.impl.Constants.DEFAULT_CAPACITY, + gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR, Float.NaN)); } public static void registerUnits(Class source) throws IllegalAccessException { @@ -210,9 +202,9 @@ public class Units { * parenthesis are allowed at all. As such, *
      *
    • Multiple units under the division bar should be located after the - * single {@code '/'} and separated by {@code '*'}: - * gas constant ought - * to have {@code "J/K*mol"} units.
    • + * single {@code '/'} and separated by {@code '*'}: gas constant ought to + * have {@code "J/K*mol"} units. *
    • Exponentiation of parenthesis should be expanded: (m/s)² = * {@code "m^2/s^2"}.
    • *
    • Exponents should also be used for expressing roots: √s = @@ -221,8 +213,10 @@ public class Units { * discouraged.
    • *
    * - * @param unit unit declaration - * @throws IllegalArgumentException if the declaration is invalid + * @param unit + * unit declaration + * @throws IllegalArgumentException + * if the declaration is invalid * @return the value of the unit * @see #get(String) get(String) * @see #registerUnit(float, String...) diff --git a/src/main/java/ru/windcorp/progressia/common/collision/AABB.java b/src/main/java/ru/windcorp/progressia/common/collision/AABB.java index fd8ffe9..ce27f68 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/AABB.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/AABB.java @@ -15,14 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; /** - * An implementation of an - * Axis-Aligned * Bounding Box. * @@ -36,17 +35,7 @@ public class AABB implements AABBoid { private final Vec3 widthSelector = new Vec3(); private final Vec3 heightSelector = new Vec3(); - public AABBWallImpl( - float ox, - float oy, - float oz, - float wx, - float wy, - float wz, - float hx, - float hy, - float hz - ) { + public AABBWallImpl(float ox, float oy, float oz, float wx, float wy, float wz, float hx, float hy, float hz) { this.originOffset.set(ox, oy, oz); this.widthSelector.set(wx, wy, wz); this.heightSelector.set(hx, hy, hz); @@ -71,13 +60,12 @@ public class AABB implements AABBoid { public static final AABB UNIT_CUBE = new AABB(0, 0, 0, 1, 1, 1); - private final Wall[] walls = new Wall[] { - new AABBWallImpl(-0.5f, -0.5f, +0.5f, +1, 0, 0, 0, +1, 0), // Top - new AABBWallImpl(-0.5f, -0.5f, -0.5f, 0, +1, 0, +1, 0, 0), // Bottom - new AABBWallImpl(+0.5f, -0.5f, -0.5f, 0, +1, 0, 0, 0, +1), // North - new AABBWallImpl(-0.5f, +0.5f, -0.5f, 0, -1, 0, 0, 0, +1), // South - new AABBWallImpl(+0.5f, +0.5f, -0.5f, -1, 0, 0, 0, 0, +1), // West - new AABBWallImpl(-0.5f, -0.5f, -0.5f, +1, 0, 0, 0, 0, +1) // East + private final Wall[] walls = new Wall[] { new AABBWallImpl(-0.5f, -0.5f, +0.5f, +1, 0, 0, 0, +1, 0), // Top + new AABBWallImpl(-0.5f, -0.5f, -0.5f, 0, +1, 0, +1, 0, 0), // Bottom + new AABBWallImpl(+0.5f, -0.5f, -0.5f, 0, +1, 0, 0, 0, +1), // North + new AABBWallImpl(-0.5f, +0.5f, -0.5f, 0, -1, 0, 0, 0, +1), // South + new AABBWallImpl(+0.5f, +0.5f, -0.5f, -1, 0, 0, 0, 0, +1), // West + new AABBWallImpl(-0.5f, -0.5f, -0.5f, +1, 0, 0, 0, 0, +1) // East }; private final Vec3 origin = new Vec3(); @@ -87,14 +75,7 @@ public class AABB implements AABBoid { this(origin.x, origin.y, origin.z, size.x, size.y, size.z); } - public AABB( - float ox, - float oy, - float oz, - float xSize, - float ySize, - float zSize - ) { + public AABB(float ox, float oy, float oz, float xSize, float ySize, float zSize) { this.origin.set(ox, oy, oz); this.size.set(xSize, ySize, zSize); } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/AABBRotator.java b/src/main/java/ru/windcorp/progressia/common/collision/AABBRotator.java new file mode 100644 index 0000000..cbacb29 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/collision/AABBRotator.java @@ -0,0 +1,134 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.collision; + +import java.util.function.Supplier; + +import com.google.common.collect.ImmutableList; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.AxisRotations; + +public class AABBRotator implements AABBoid { + + private class AABBRotatorWall implements Wall { + + private final int id; + + public AABBRotatorWall(int id) { + this.id = id; + } + + @Override + public void getOrigin(Vec3 output) { + parent.getWall(id).getOrigin(output); + AxisRotations.resolve(output, upSupplier.get(), output); + } + + @Override + public void getWidth(Vec3 output) { + parent.getWall(id).getWidth(output); + AxisRotations.resolve(output, upSupplier.get(), output); + } + + @Override + public void getHeight(Vec3 output) { + parent.getWall(id).getHeight(output); + AxisRotations.resolve(output, upSupplier.get(), output); + } + + } + + private final Supplier upSupplier; + private final Supplier hingeSupplier; + private final AABBoid parent; + + private final AABBRotatorWall[] walls = new AABBRotatorWall[AbsFace.BLOCK_FACE_COUNT]; + + { + for (int id = 0; id < walls.length; ++id) { + walls[id] = new AABBRotatorWall(id); + } + } + + public AABBRotator(Supplier upSupplier, Supplier hingeSupplier, AABBoid parent) { + this.upSupplier = upSupplier; + this.hingeSupplier = hingeSupplier; + this.parent = parent; + } + + @Override + public void setOrigin(Vec3 origin) { + Vec3 relativeOrigin = Vectors.grab3(); + Vec3 hinge = hingeSupplier.get(); + + origin.sub(hinge, relativeOrigin); + AxisRotations.relativize(relativeOrigin, upSupplier.get(), relativeOrigin); + relativeOrigin.add(hinge); + + parent.setOrigin(relativeOrigin); + + Vectors.release(relativeOrigin); + } + + @Override + public void moveOrigin(Vec3 displacement) { + parent.moveOrigin(displacement); + } + + @Override + public void getOrigin(Vec3 output) { + parent.getOrigin(output); + Vec3 hinge = hingeSupplier.get(); + + output.sub(hinge); + AxisRotations.resolve(output, upSupplier.get(), output); + output.add(hinge); + } + + @Override + public void getSize(Vec3 output) { + parent.getSize(output); + AxisRotations.resolve(output, upSupplier.get(), output); + output.abs(); + } + + @Override + public Wall getWall(int faceId) { + return walls[faceId]; + } + + public static CollisionModel rotate(Supplier upSupplier, Supplier hingeSupplier, CollisionModel parent) { + if (parent instanceof AABBoid) { + return new AABBRotator(upSupplier, hingeSupplier, (AABBoid) parent); + } else if (parent instanceof CompoundCollisionModel) { + ImmutableList.Builder models = ImmutableList.builder(); + + for (CollisionModel original : ((CompoundCollisionModel) parent).getModels()) { + models.add(rotate(upSupplier, hingeSupplier, original)); + } + + return new CompoundCollisionModel(models.build()); + } else { + throw new RuntimeException("not supported"); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java b/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java index ab2cd80..3a36b8b 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java @@ -15,11 +15,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public interface AABBoid extends CollisionModel { @@ -27,7 +27,7 @@ public interface AABBoid extends CollisionModel { void getSize(Vec3 output); - default Wall getWall(BlockFace face) { + default Wall getWall(AbsFace face) { return getWall(face.getId()); } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/Collideable.java b/src/main/java/ru/windcorp/progressia/common/collision/Collideable.java index 8db7805..14ca2c3 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/Collideable.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/Collideable.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; @@ -26,10 +26,11 @@ public interface Collideable { CollisionModel getCollisionModel(); /** - * Invoked by {@link Collider} when two entities are about to collide. - * The world is at the moment of collision. + * Invoked by {@link Collider} when two entities are about to collide. The + * world is at the moment of collision. * - * @param other the colliding object + * @param other + * the colliding object * @return {@code true} iff the collision should not be handled normally * (e.g. this object has disappeared) */ @@ -37,8 +38,8 @@ public interface Collideable { /** * Returns the mass of this {@link Collideable} that should be used to - * calculate collisions. - * Collision mass must be a positive number. Positive infinity is allowed. + * calculate collisions. Collision mass must be a positive number. Positive + * infinity is allowed. * * @return this object's collision mass */ diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CollisionModel.java b/src/main/java/ru/windcorp/progressia/common/collision/CollisionModel.java index 9ade6af..209063a 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/CollisionModel.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/CollisionModel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java b/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java index 4826bce..88a57e1 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision; import java.util.function.Consumer; @@ -30,11 +30,7 @@ public class CollisionPathComputer { private static final float PADDING = 0.5f; - public static void forEveryBlockInCollisionPath( - Collideable coll, - float maxTime, - Consumer action - ) { + public static void forEveryBlockInCollisionPath(Collideable coll, float maxTime, Consumer action) { Vec3 displacement = Vectors.grab3(); coll.getCollideableVelocity(displacement); displacement.mul(maxTime); @@ -44,11 +40,7 @@ public class CollisionPathComputer { Vectors.release(displacement); } - private static void handleModel( - CollisionModel model, - Vec3 displacement, - Consumer action - ) { + private static void handleModel(CollisionModel model, Vec3 displacement, Consumer action) { if (model instanceof CompoundCollisionModel) { for (CollisionModel subModel : ((CompoundCollisionModel) model).getModels()) { handleModel(subModel, displacement, action); @@ -71,21 +63,13 @@ public class CollisionPathComputer { Vec3i pos = Vectors.grab3i(); - for ( - pos.x = (int) floor(origin.x + min(0, size.x) + min(0, displacement.x) - PADDING); - pos.x <= (int) ceil(origin.x + max(0, size.x) + max(0, displacement.x) + PADDING); - pos.x += 1 - ) { - for ( - pos.y = (int) floor(origin.y + min(0, size.y) + min(0, displacement.y) - PADDING); - pos.y <= (int) ceil(origin.y + max(0, size.y) + max(0, displacement.y) + PADDING); - pos.y += 1 - ) { - for ( - pos.z = (int) floor(origin.z + min(0, size.z) + min(0, displacement.z) - PADDING); - pos.z <= (int) ceil(origin.z + max(0, size.z) + max(0, displacement.z) + PADDING); - pos.z += 1 - ) { + for (pos.x = (int) floor(origin.x + min(0, size.x) + min(0, displacement.x) - PADDING); pos.x <= (int) ceil( + origin.x + max(0, size.x) + max(0, displacement.x) + PADDING); pos.x += 1) { + for (pos.y = (int) floor(origin.y + min(0, size.y) + min(0, displacement.y) - PADDING); pos.y <= (int) ceil( + origin.y + max(0, size.y) + max(0, displacement.y) + PADDING); pos.y += 1) { + for (pos.z = (int) floor( + origin.z + min(0, size.z) + min(0, displacement.z) - PADDING); pos.z <= (int) ceil( + origin.z + max(0, size.z) + max(0, displacement.z) + PADDING); pos.z += 1) { action.accept(pos); } } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java b/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java index 6f5ec24..a91dfdf 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision; import java.util.Collection; diff --git a/src/main/java/ru/windcorp/progressia/common/collision/TransformedCollisionModel.java b/src/main/java/ru/windcorp/progressia/common/collision/TransformedCollisionModel.java index 96bfbee..9622423 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/TransformedCollisionModel.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/TransformedCollisionModel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java b/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java index 4c33ad2..95fe1d3 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java @@ -15,12 +15,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TranslatedAABB implements AABBoid { @@ -51,7 +51,7 @@ public class TranslatedAABB implements AABBoid { private AABBoid parent; private final Vec3 translation = new Vec3(); - private final TranslatedAABBWall[] walls = new TranslatedAABBWall[BlockFace.BLOCK_FACE_COUNT]; + private final TranslatedAABBWall[] walls = new TranslatedAABBWall[AbsFace.BLOCK_FACE_COUNT]; { for (int id = 0; id < walls.length; ++id) { diff --git a/src/main/java/ru/windcorp/progressia/common/collision/Wall.java b/src/main/java/ru/windcorp/progressia/common/collision/Wall.java index 91ca006..91e9f72 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/Wall.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/Wall.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; diff --git a/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java b/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java index 69d2d4a..9dff95d 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision; import java.util.ArrayList; @@ -24,7 +24,7 @@ import java.util.Collection; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.LowOverheadCache; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class WorldCollisionHelper { @@ -68,25 +68,22 @@ public class WorldCollisionHelper { /** * Changes the state of this helper's {@link #getCollideable()} so it is - * ready to adequately handle - * collisions with the {@code collideable} that might happen in the next - * {@code maxTime} seconds. - * This helper is only valid for checking collisions with the given - * Collideable and only within + * ready to adequately handle collisions with the {@code collideable} that + * might happen in the next {@code maxTime} seconds. This helper is only + * valid for checking collisions with the given Collideable and only within * the given time limit. * - * @param collideable the {@link Collideable} that collisions will be - * checked against - * @param maxTime maximum collision time + * @param collideable + * the {@link Collideable} that collisions will be checked + * against + * @param maxTime + * maximum collision time */ - public void tuneToCollideable(WorldData world, Collideable collideable, float maxTime) { + public void tuneToCollideable(DefaultWorldData world, Collideable collideable, float maxTime) { activeBlockModels.forEach(blockModelCache::release); activeBlockModels.clear(); - CollisionPathComputer.forEveryBlockInCollisionPath( - collideable, - maxTime, - v -> addModel(world.getCollisionModelOfBlock(v), v) - ); + CollisionPathComputer.forEveryBlockInCollisionPath(collideable, maxTime, + v -> addModel(world.getCollisionModelOfBlock(v), v)); } private void addModel(CollisionModel model, Vec3i pos) { diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java index 5fab3d8..ed42594 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java @@ -25,7 +25,7 @@ import ru.windcorp.progressia.common.collision.colliders.Collider.ColliderWorksp import ru.windcorp.progressia.common.collision.colliders.Collider.Collision; import ru.windcorp.progressia.common.util.Matrices; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; class AABBoidCollider { @@ -50,7 +50,7 @@ class AABBoidCollider { computeCollisionVelocity(collisionVelocity, obstacleBody, colliderBody); // For every wall of collision space - for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { + for (int i = 0; i < AbsFace.BLOCK_FACE_COUNT; ++i) { Wall wall = originCollisionSpace.getWall(i); Collision collision = computeWallCollision( @@ -122,46 +122,51 @@ class AABBoidCollider { return output; } + // @formatter:off /* - * Here we determine whether a collision has actually happened, and if it - * did, at what moment. - * The basic idea is to compute the moment of collision and impact - * coordinates in wall coordinate space. - * Then, we can check impact coordinates to determine if we actually hit the - * wall or flew by and then - * check time to make sure the collision is not too far in the future and - * not in the past. + * Here we determine whether a collision has actually happened, and if it did, at what moment. + * + * The basic idea is to compute the moment of collision and impact coordinates in wall coordinate space. + * Then, we can check impact coordinates to determine if we actually hit the wall or flew by and then + * check time to make sure the collision is not too far in the future and not in the past. + * * DETAILED EXPLANATION: - * Consider a surface defined by an origin r_wall and two noncollinear - * nonzero vectors w and h. + * + * Consider a surface defined by an origin r_wall and two noncollinear nonzero vectors w and h. * Consider a line defined by an origin r_line and a nonzero vector v. + * * Then, a collision occurs if there exist x, y and t such that - * ______ _ - * r_line + v * t + * ______ _ + * r_line + v * t + * * and - * ______ _ _ - * r_wall + w * x + h * y - * describe the same location (indeed, this corresponds to a collision at - * moment t0 + t - * with a point on the wall with coordinates (x; y) in (w; h) coordinate - * system). + * ______ _ _ + * r_wall + w * x + h * y + * + * describe the same location (indeed, this corresponds to a collision at moment t0 + t + * with a point on the wall with coordinates (x; y) in (w; h) coordinate system). + * * Therefore, - * ______ _ ______ _ _ - * r_line + v*t = r_wall + w*x + h*y; - * _ ⎡w_x h_x -v_x⎤ ⎡x⎤ _ ______ ______ - * r = ⎢w_y h_y -v_y⎥ * ⎢y⎥, where r = r_line - r_wall; - * ⎣w_z h_z -v_z⎦ ⎣t⎦ - * ⎡x⎤ ⎡w_x h_x -v_x⎤ -1 _ - * ⎢y⎥ = ⎢w_y h_y -v_y⎥ * r, if the matrix is invertible. - * ⎣t⎦ ⎣w_z h_z -v_z⎦ + * ______ _ ______ _ _ + * r_line + v*t = r_wall + w*x + h*y; + * + * _ ⎡w_x h_x -v_x⎤ ⎡x⎤ _ ______ ______ + * r = ⎢w_y h_y -v_y⎥ * ⎢y⎥, where r = r_line - r_wall; + * ⎣w_z h_z -v_z⎦ ⎣t⎦ + * + * ⎡x⎤ ⎡w_x h_x -v_x⎤ -1 _ + * ⎢y⎥ = ⎢w_y h_y -v_y⎥ * r, if the matrix is invertible. + * ⎣t⎦ ⎣w_z h_z -v_z⎦ + * * Then, one only needs to ensure that: - * 0 < x < 1, - * 0 < y < 1, and - * 0 < t < T, where T is remaining tick time. - * If the matrix is not invertible or any of the conditions are not met, no - * collision happened. + * 0 < x < 1, + * 0 < y < 1, and + * 0 < t < T, where T is remaining tick time. + * + * If the matrix is not invertible or any of the conditions are not met, no collision happened. * If all conditions are satisfied, then the moment of impact is t0 + t. */ + // @formatter:on private static Collision computeWallCollision( Wall obstacleWall, AABBoid colliderModel, diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AnythingWithCompoundCollider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AnythingWithCompoundCollider.java index 559de13..a1f3383 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AnythingWithCompoundCollider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AnythingWithCompoundCollider.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.collision.colliders; import ru.windcorp.progressia.common.collision.Collideable; @@ -26,26 +26,13 @@ import ru.windcorp.progressia.common.collision.colliders.Collider.Collision; class AnythingWithCompoundCollider { - static Collider.Collision computeModelCollision( - Collideable aBody, - Collideable bBody, - CompoundCollisionModel aModel, - CollisionModel bModel, - float tickLength, - ColliderWorkspace workspace - ) { + static Collider.Collision computeModelCollision(Collideable aBody, Collideable bBody, CompoundCollisionModel aModel, + CollisionModel bModel, float tickLength, ColliderWorkspace workspace) { Collision result = null; for (CollisionModel aModelPart : aModel.getModels()) { - Collision collision = Collider.getCollision( - aBody, - bBody, - aModelPart, - bModel, - tickLength, - workspace - ); + Collision collision = Collider.getCollision(aBody, bBody, aModelPart, bModel, tickLength, workspace); // Update result if (collision != null) { diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java index 56bc8ad..9b97e40 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java @@ -27,7 +27,7 @@ import glm.vec._3.Vec3; import ru.windcorp.progressia.common.collision.*; import ru.windcorp.progressia.common.util.LowOverheadCache; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class Collider { @@ -36,7 +36,7 @@ public class Collider { /** * Dear Princess Celestia, *

    - * When {@linkplain #advanceTime(Collection, Collision, WorldData, float) + * When {@linkplain #advanceTime(Collection, Collision, DefaultWorldData, float) * advancing time}, * time step for all entities except currently colliding bodies is * the current @@ -61,7 +61,7 @@ public class Collider { public static void performCollisions( List colls, - WorldData world, + DefaultWorldData world, float tickLength, ColliderWorkspace workspace ) { @@ -96,7 +96,7 @@ public class Collider { private static Collision getFirstCollision( List colls, float tickLength, - WorldData world, + DefaultWorldData world, ColliderWorkspace workspace ) { Collision result = null; @@ -126,7 +126,7 @@ public class Collider { private static void tuneWorldCollisionHelper( Collideable coll, float tickLength, - WorldData world, + DefaultWorldData world, ColliderWorkspace workspace ) { WorldCollisionHelper wch = workspace.worldCollisionHelper; @@ -194,7 +194,7 @@ public class Collider { Collision collision, Collection colls, - WorldData world, + DefaultWorldData world, float tickLength, ColliderWorkspace workspace ) { @@ -212,66 +212,72 @@ public class Collider { handlePhysics(collision); } + // @formatter:off /* * Here we compute the change in body velocities due to a collision. + * * We make the following simplifications: - * 1) The bodies are perfectly rigid; - * 2) The collision is perfectly inelastic - * (no bouncing); - * 3) The bodies are spherical; - * 4) No tangential friction exists - * (bodies do not experience friction when sliding against each other); - * 5) Velocities are not relativistic. + * 1) The bodies are perfectly rigid; + * 2) The collision is perfectly inelastic + * (no bouncing); + * 3) The bodies are spherical; + * 4) No tangential friction exists + * (bodies do not experience friction when sliding against each other); + * 5) Velocities are not relativistic. + * * Angular momentum is ignored per 3) and 4), - * e.g. when something pushes an end of a long stick, the stick does not - * rotate. + * e.g. when something pushes an end of a long stick, the stick does not rotate. + * * DETAILED EXPLANATION: - * Two spherical (sic) bodies, a and b, experience a perfectly inelastic - * collision + * + * Two spherical (sic) bodies, a and b, experience a perfectly inelastic collision * along a unit vector - * _ _ _ _ _ - * n = (w ⨯ h) / (|w ⨯ h|), - * _ _ + * _ _ _ _ _ + * n = (w ⨯ h) / (|w ⨯ h|), + * _ _ * where w and h are two noncollinear nonzero vectors on the dividing plane. - * ___ ___ + * ___ ___ * Body masses and velocities are M_a, M_b and v_a, v_b, respectively. - * ___ ___ + * ___ ___ * After the collision desired velocities are u_a and u_b, respectively. - * _ - * (Notation convention: suffix 'n' denotes a vector projection onto vector - * n, + * _ + * (Notation convention: suffix 'n' denotes a vector projection onto vector n, * and suffix 't' denotes a vector projection onto the dividing plane.) - * Consider the law of conservation of momentum for axis n and the dividing - * plane: - * ____________ ____________ ________________ - * n: ⎧ p_a_before_n + p_b_before_n = p_common_after_n; - * ⎨ ___________ ____________ - * t: ⎩ p_i_after_t = p_i_before_t for any i in {a, b}. + * + * Consider the law of conservation of momentum for axis n and the dividing plane: + * ____________ ____________ ________________ + * n: ⎧ p_a_before_n + p_b_before_n = p_common_after_n; + * ⎨ ___________ ____________ + * t: ⎩ p_i_after_t = p_i_before_t for any i in {a, b}. + * * Expressing all p_* in given terms: - * ___ _ ___ _ ___ ___ ____ ____ - * n: ⎧ M_a * (v_a ⋅ n) + M_b * (v_b ⋅ n) = (M_a + M_b) * u_n, where u_n ≡ - * u_an = u_bn; - * ⎨ ____ ___ _ ___ _ - * t: ⎩ u_it = v_i - n * (v_i ⋅ n) for any i in {a, b}. + * ___ _ ___ _ ___ ___ ____ ____ + * n: ⎧ M_a * (v_a ⋅ n) + M_b * (v_b ⋅ n) = (M_a + M_b) * u_n, where u_n ≡ u_an = u_bn; + * ⎨ ____ ___ _ ___ _ + * t: ⎩ u_it = v_i - n * (v_i ⋅ n) for any i in {a, b}. + * * Therefore: - * ___ _ ___ _ ___ _ - * u_n = n * ( M_a/(M_a + M_b) * v_a ⋅ n + M_b/(M_a + M_b) * v_b ⋅ n ); + * ___ _ ___ _ ___ _ + * u_n = n * ( M_a/(M_a + M_b) * v_a ⋅ n + M_b/(M_a + M_b) * v_b ⋅ n ); + * * or, equivalently, - * ___ _ ___ _ ___ _ - * u_n = n * ( m_a * v_a ⋅ n + m_b * v_b ⋅ n ), + * ___ _ ___ _ ___ _ + * u_n = n * ( m_a * v_a ⋅ n + m_b * v_b ⋅ n ), + * * where m_a and m_b are relative masses (see below). + * * Finally, - * ___ ____ ___ - * u_i = u_it + u_n for any i in {a, b}. - * The usage of relative masses m_i permits a convenient generalization of - * the algorithm - * for infinite masses, signifying masses "significantly greater" than - * finite masses: - * 1) If both M_a and M_b are finite, let m_i = M_i / (M_a + M_b) for any i - * in {a, b}. - * 2) If M_i is finite but M_j is infinite, let m_i = 0 and m_j = 1. - * 3) If both M_a and M_b are infinite, let m_i = 1/2 for any i in {a, b}. + * ___ ____ ___ + * u_i = u_it + u_n for any i in {a, b}. + * + * The usage of relative masses m_i permits a convenient generalization of the algorithm + * for infinite masses, signifying masses "significantly greater" than finite masses: + * + * 1) If both M_a and M_b are finite, let m_i = M_i / (M_a + M_b) for any i in {a, b}. + * 2) If M_i is finite but M_j is infinite, let m_i = 0 and m_j = 1. + * 3) If both M_a and M_b are infinite, let m_i = 1/2 for any i in {a, b}. */ + // @formatter:on private static void handlePhysics(Collision collision) { // Fuck JGLM Vec3 n = Vectors.grab3(); @@ -355,7 +361,7 @@ public class Collider { private static void advanceTime( Collection colls, Collision exceptions, - WorldData world, + DefaultWorldData world, float step ) { world.advanceTime(step); diff --git a/src/main/java/ru/windcorp/progressia/common/comms/CommsChannel.java b/src/main/java/ru/windcorp/progressia/common/comms/CommsChannel.java index 288b5dd..32e8829 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/CommsChannel.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/CommsChannel.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.comms; import java.io.IOException; @@ -56,15 +56,9 @@ public abstract class CommsChannel { protected abstract void doSendPacket(Packet packet) throws IOException; - private synchronized void sendPacket( - Packet packet, - State expectedState, - String errorMessage - ) { + private synchronized void sendPacket(Packet packet, State expectedState, String errorMessage) { if (getState() != expectedState) { - throw new IllegalStateException( - String.format(errorMessage, this, getState()) - ); + throw new IllegalStateException(String.format(errorMessage, this, getState())); } try { @@ -75,27 +69,15 @@ public abstract class CommsChannel { } public synchronized void sendPacket(Packet packet) { - sendPacket( - packet, - State.CONNECTED, - "Client %s is in state %s and cannot receive packets normally" - ); + sendPacket(packet, State.CONNECTED, "Client %s is in state %s and cannot receive packets normally"); } public synchronized void sendConnectingPacket(Packet packet) { - sendPacket( - packet, - State.CONNECTING, - "Client %s is in state %s and is no longer connecting" - ); + sendPacket(packet, State.CONNECTING, "Client %s is in state %s and is no longer connecting"); } public synchronized void sendDisconnectingPacket(Packet packet) { - sendPacket( - packet, - State.CONNECTING, - "Client %s is in state %s and is no longer disconnecting" - ); + sendPacket(packet, State.CONNECTING, "Client %s is in state %s and is no longer disconnecting"); } public abstract void disconnect(); diff --git a/src/main/java/ru/windcorp/progressia/common/comms/CommsListener.java b/src/main/java/ru/windcorp/progressia/common/comms/CommsListener.java index 7445e93..e133cf8 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/CommsListener.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/CommsListener.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.comms; import java.io.IOException; diff --git a/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlData.java b/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlData.java index 46e4e94..d90505b 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlData.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlData.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.comms.controls; import ru.windcorp.progressia.common.util.namespaces.Namespaced; diff --git a/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java index cd884e8..59a8529 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.comms.controls; import ru.windcorp.progressia.common.util.namespaces.NamespacedFactoryRegistry; diff --git a/src/main/java/ru/windcorp/progressia/common/comms/controls/PacketControl.java b/src/main/java/ru/windcorp/progressia/common/comms/controls/PacketControl.java index d5abd39..2d352bb 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/controls/PacketControl.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/controls/PacketControl.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.comms.controls; import java.io.DataInput; diff --git a/src/main/java/ru/windcorp/progressia/common/comms/packets/Packet.java b/src/main/java/ru/windcorp/progressia/common/comms/packets/Packet.java index 5421028..8669eb3 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/packets/Packet.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/packets/Packet.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.comms.packets; import java.io.DataInput; diff --git a/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java b/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java index 6bc7901..8ee2c60 100644 --- a/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java +++ b/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.hacks; import java.lang.reflect.Constructor; @@ -29,15 +29,14 @@ import com.google.common.util.concurrent.MoreExecutors; import ru.windcorp.progressia.common.util.crash.CrashReports; /** - * This class had to be written because there is not legal way to instantiate a - * non-async - * {@link EventBus} with both a custom identifier and a custom exception - * handler. Which - * is a shame. Guava maintainers know about the issue but have rejected - * solutions multiple - * times without a clearly stated reason; looks like some dirty - * reflection will - * have to do. + * This class had to be written because there is no legal way to instantiate a + * non-async {@link EventBus} with both a custom identifier and a custom + * exception handler. Which is a shame. Guava maintainers know about the issue + * but have rejected solutions multiple times without a clearly stated + * reason; looks like some dirty reflection will have to do. + *

    + * When explicitly referencing this class, please mention its usage in + * implementation notes because it is unreliable long-term. * * @author javapony */ diff --git a/src/main/java/ru/windcorp/progressia/common/resource/Resource.java b/src/main/java/ru/windcorp/progressia/common/resource/Resource.java index 6cd4d32..41cf621 100644 --- a/src/main/java/ru/windcorp/progressia/common/resource/Resource.java +++ b/src/main/java/ru/windcorp/progressia/common/resource/Resource.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.resource; import java.io.IOException; @@ -34,7 +34,7 @@ import ru.windcorp.progressia.common.util.Named; import ru.windcorp.progressia.common.util.crash.CrashReports; public class Resource extends Named { - + private final ResourceReader resourceReader; public Resource(String name, ResourceReader resourceReader) { @@ -45,7 +45,7 @@ public class Resource extends Named { public InputStream getInputStream() { return getResourceReader().read(getName()); } - + public ResourceReader getResourceReader() { return resourceReader; } diff --git a/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java b/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java index 33db64d..fcfc43f 100644 --- a/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java +++ b/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java @@ -15,18 +15,18 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.resource; public class ResourceManager { - + private static final ResourceReader CLASSPATH_READER = new ClasspathResourceReader(); private static final ResourceReader FILESYSTEM_READER = new FilesystemResourceReader(); public static Resource getResource(String name) { return new Resource(name, CLASSPATH_READER); } - + public static Resource getFileResource(String name) { return new Resource(name, FILESYSTEM_READER); } diff --git a/src/main/java/ru/windcorp/progressia/common/resource/ResourceReader.java b/src/main/java/ru/windcorp/progressia/common/resource/ResourceReader.java index 1f95f2c..49c221c 100644 --- a/src/main/java/ru/windcorp/progressia/common/resource/ResourceReader.java +++ b/src/main/java/ru/windcorp/progressia/common/resource/ResourceReader.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.common.resource; import java.io.InputStream; public interface ResourceReader { - + InputStream read(String name); } diff --git a/src/main/java/ru/windcorp/progressia/common/state/AbstractStatefulObjectLayout.java b/src/main/java/ru/windcorp/progressia/common/state/AbstractStatefulObjectLayout.java index b2feb80..6752fd7 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/AbstractStatefulObjectLayout.java +++ b/src/main/java/ru/windcorp/progressia/common/state/AbstractStatefulObjectLayout.java @@ -15,15 +15,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -public abstract class AbstractStatefulObjectLayout - extends StatefulObjectLayout { +public abstract class AbstractStatefulObjectLayout extends StatefulObjectLayout { public AbstractStatefulObjectLayout(String objectId) { super(objectId); @@ -34,12 +33,7 @@ public abstract class AbstractStatefulObjectLayout protected abstract StateField getField(int fieldIndex); @Override - public void read( - StatefulObject object, - DataInput input, - IOContext context - ) - throws IOException { + public void read(StatefulObject object, DataInput input, IOContext context) throws IOException { int fieldCount = getFieldCount(); for (int i = 0; i < fieldCount; ++i) { @@ -53,12 +47,7 @@ public abstract class AbstractStatefulObjectLayout } @Override - public void write( - StatefulObject object, - DataOutput output, - IOContext context - ) - throws IOException { + public void write(StatefulObject object, DataOutput output, IOContext context) throws IOException { int fieldCount = getFieldCount(); for (int i = 0; i < fieldCount; ++i) { diff --git a/src/main/java/ru/windcorp/progressia/common/state/HashMapStateStorage.java b/src/main/java/ru/windcorp/progressia/common/state/HashMapStateStorage.java index 52d446f..56ee25d 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/HashMapStateStorage.java +++ b/src/main/java/ru/windcorp/progressia/common/state/HashMapStateStorage.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; import gnu.trove.map.TIntIntMap; diff --git a/src/main/java/ru/windcorp/progressia/common/state/IOContext.java b/src/main/java/ru/windcorp/progressia/common/state/IOContext.java index b18f875..c309596 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/IOContext.java +++ b/src/main/java/ru/windcorp/progressia/common/state/IOContext.java @@ -15,13 +15,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; public enum IOContext { - COMMS, - SAVE, - INTERNAL; + COMMS, SAVE, INTERNAL; } diff --git a/src/main/java/ru/windcorp/progressia/common/state/InspectingStatefulObjectLayout.java b/src/main/java/ru/windcorp/progressia/common/state/InspectingStatefulObjectLayout.java index 8b0a9fe..d32af14 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/InspectingStatefulObjectLayout.java +++ b/src/main/java/ru/windcorp/progressia/common/state/InspectingStatefulObjectLayout.java @@ -15,14 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; import java.util.ArrayList; import java.util.List; -public class InspectingStatefulObjectLayout - extends AbstractStatefulObjectLayout { +public class InspectingStatefulObjectLayout extends AbstractStatefulObjectLayout { private final List fields = new ArrayList<>(); @@ -48,11 +47,7 @@ public class InspectingStatefulObjectLayout } public StatefulObjectLayout compile() { - return new OptimizedStatefulObjectLayout( - getObjectId(), - fields, - fieldIndexCounters - ); + return new OptimizedStatefulObjectLayout(getObjectId(), fields, fieldIndexCounters); } private T registerField(T field) { @@ -71,13 +66,7 @@ public class InspectingStatefulObjectLayout @Override public IntStateField build() { - return registerField( - new IntStateField( - id, - isLocal, - fieldIndexCounters.getIntsThenIncrement() - ) - ); + return registerField(new IntStateField(id, isLocal, fieldIndexCounters.getIntsThenIncrement())); } } @@ -105,10 +94,7 @@ public class InspectingStatefulObjectLayout public void setOrdinal(int ordinal) { if (ordinal != fields.size()) { throw new IllegalStateException( - "This field is going to receive ordinal " - + fields.size() + ", requested ordinal " - + ordinal - ); + "This field is going to receive ordinal " + fields.size() + ", requested ordinal " + ordinal); } } diff --git a/src/main/java/ru/windcorp/progressia/common/state/IntStateField.java b/src/main/java/ru/windcorp/progressia/common/state/IntStateField.java index abf8573..7390187 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/IntStateField.java +++ b/src/main/java/ru/windcorp/progressia/common/state/IntStateField.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; import java.io.DataInput; @@ -24,11 +24,7 @@ import java.io.IOException; public class IntStateField extends StateField { - public IntStateField( - String id, - boolean isLocal, - int index - ) { + public IntStateField(String id, boolean isLocal, int index) { super(id, isLocal, index); } @@ -45,22 +41,12 @@ public class IntStateField extends StateField { } @Override - public void read( - StatefulObject object, - DataInput input, - IOContext context - ) - throws IOException { + public void read(StatefulObject object, DataInput input, IOContext context) throws IOException { object.getStorage().setInt(getIndex(), input.readInt()); } @Override - public void write( - StatefulObject object, - DataOutput output, - IOContext context - ) - throws IOException { + public void write(StatefulObject object, DataOutput output, IOContext context) throws IOException { output.writeInt(object.getStorage().getInt(getIndex())); } diff --git a/src/main/java/ru/windcorp/progressia/common/state/OptimizedStateStorage.java b/src/main/java/ru/windcorp/progressia/common/state/OptimizedStateStorage.java index 478fbac..fbedec7 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/OptimizedStateStorage.java +++ b/src/main/java/ru/windcorp/progressia/common/state/OptimizedStateStorage.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; public class OptimizedStateStorage extends StateStorage { diff --git a/src/main/java/ru/windcorp/progressia/common/state/OptimizedStatefulObjectLayout.java b/src/main/java/ru/windcorp/progressia/common/state/OptimizedStatefulObjectLayout.java index 1158ab0..c9269c2 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/OptimizedStatefulObjectLayout.java +++ b/src/main/java/ru/windcorp/progressia/common/state/OptimizedStatefulObjectLayout.java @@ -15,24 +15,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; import java.util.List; import com.google.common.collect.ImmutableList; -public class OptimizedStatefulObjectLayout - extends AbstractStatefulObjectLayout { +public class OptimizedStatefulObjectLayout extends AbstractStatefulObjectLayout { private final List fields; private final PrimitiveCounters sizes; - public OptimizedStatefulObjectLayout( - String objectId, - List fields, - PrimitiveCounters counters - ) { + public OptimizedStatefulObjectLayout(String objectId, List fields, PrimitiveCounters counters) { super(objectId); this.fields = ImmutableList.copyOf(fields); this.sizes = new PrimitiveCounters(counters); diff --git a/src/main/java/ru/windcorp/progressia/common/state/PrimitiveCounters.java b/src/main/java/ru/windcorp/progressia/common/state/PrimitiveCounters.java index d3e2dbb..243d62a 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/PrimitiveCounters.java +++ b/src/main/java/ru/windcorp/progressia/common/state/PrimitiveCounters.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; class PrimitiveCounters { diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java b/src/main/java/ru/windcorp/progressia/common/state/StateChange.java similarity index 94% rename from src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java rename to src/main/java/ru/windcorp/progressia/common/state/StateChange.java index 93d5f08..38638a7 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StateChange.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package ru.windcorp.progressia.server.world.tasks; +package ru.windcorp.progressia.common.state; @FunctionalInterface public interface StateChange { diff --git a/src/main/java/ru/windcorp/progressia/common/state/StateChanger.java b/src/main/java/ru/windcorp/progressia/common/state/StateChanger.java index cc8cd5a..a93e64e 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StateChanger.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StateChanger.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; public interface StateChanger { diff --git a/src/main/java/ru/windcorp/progressia/common/state/StateField.java b/src/main/java/ru/windcorp/progressia/common/state/StateField.java index ca88c4f..1e512ef 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StateField.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StateField.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; import java.io.DataInput; @@ -29,11 +29,7 @@ public abstract class StateField extends Namespaced { private final boolean isLocal; private final int index; - public StateField( - String id, - boolean isLocal, - int index - ) { + public StateField(String id, boolean isLocal, int index) { super(id); this.isLocal = isLocal; this.index = index; @@ -47,19 +43,9 @@ public abstract class StateField extends Namespaced { return index; } - public abstract void read( - StatefulObject object, - DataInput input, - IOContext context - ) - throws IOException; + public abstract void read(StatefulObject object, DataInput input, IOContext context) throws IOException; - public abstract void write( - StatefulObject object, - DataOutput output, - IOContext context - ) - throws IOException; + public abstract void write(StatefulObject object, DataOutput output, IOContext context) throws IOException; public abstract void copy(StatefulObject from, StatefulObject to); diff --git a/src/main/java/ru/windcorp/progressia/common/state/StateFieldBuilder.java b/src/main/java/ru/windcorp/progressia/common/state/StateFieldBuilder.java index 97c7176..935129a 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StateFieldBuilder.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StateFieldBuilder.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; public interface StateFieldBuilder { diff --git a/src/main/java/ru/windcorp/progressia/common/state/StateStorage.java b/src/main/java/ru/windcorp/progressia/common/state/StateStorage.java index 2f999f0..647ae00 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StateStorage.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StateStorage.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; public abstract class StateStorage { diff --git a/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java b/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java index 39f5b58..39714b6 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; import java.io.DataInput; @@ -26,24 +26,22 @@ import java.util.Objects; import ru.windcorp.progressia.common.util.namespaces.Namespaced; /** - * An abstract class describing objects that have trackable state, - * such as blocks, tiles or entities. This class contains the declaration of - * the state mechanics - * (implementation of which is mostly delegated to + * An abstract class describing objects that have trackable state, such as + * blocks, tiles or entities. This class contains the declaration of the state + * mechanics (implementation of which is mostly delegated to * {@link StatefulObjectLayout}). - *

    Structure

    - * Stateful objects are characterized by their likeness and state. + *

    Structure

    Stateful objects are characterized by their + * likeness and state. *

    * An object's likeness is the combination of the object's runtime class (as in * {@link #getClass()}) and its ID. Objects that are "alike" share the same - * internal structure, represented by a common - * {@linkplain StatefulObjectLayout layout}. Likeness can be tested with - * {@link #isLike(Object)}. + * internal structure, represented by a common {@linkplain StatefulObjectLayout + * layout}. Likeness can be tested with {@link #isLike(Object)}. *

    * An object's state is the combination of the values of an object's * {@linkplain StateField state fields}. State fields are different from object - * fields as described by the Java language: not every object field is a part - * of its state, although state fields are usually implemented as object fields. + * fields as described by the Java language: not every object field is a part of + * its state, although state fields are usually implemented as object fields. * Each state field is, in its turn, has the following characteristics: *

      *
    • ID, distinct from the ID of the stateful object to which it belongs. @@ -58,10 +56,7 @@ public abstract class StatefulObject extends Namespaced { private final StateStorage storage; - public StatefulObject( - StatefulObjectRegistry type, - String id - ) { + public StatefulObject(StatefulObjectRegistry type, String id) { super(id); this.layout = type.getLayout(getId()); this.storage = getLayout().createStorage(); @@ -69,8 +64,8 @@ public abstract class StatefulObject extends Namespaced { /** * Returns the {@link StatefulObjectLayout} describing objects that are - * {@linkplain #isLike(Object) "like"} this object. - * You probably don't need this. + * {@linkplain #isLike(Object) "like"} this object. You probably don't need + * this. * * @return this object's field layout */ @@ -106,8 +101,10 @@ public abstract class StatefulObject extends Namespaced { * sequence of invocations must occur during construction of each object * with the same ID. * - * @param namespace the namespace of the new field - * @param name the name of the new field + * @param namespace + * the namespace of the new field + * @param name + * the name of the new field * @return a configured builder */ protected StateFieldBuilder field(String id) { @@ -128,10 +125,13 @@ public abstract class StatefulObject extends Namespaced { * from {@code input}. If {@code context == COMMS}, the state of local * fields is unspecified after this operation. * - * @param input a {@link DataInput} that a state can be read from - * @param context the context - * @throws IOException if the state is encoded poorly or an error occurs - * in {@code input} + * @param input + * a {@link DataInput} that a state can be read from + * @param context + * the context + * @throws IOException + * if the state is encoded poorly or an error occurs in + * {@code input} */ public void read(DataInput input, IOContext context) throws IOException { getLayout().read(this, input, context); @@ -141,9 +141,12 @@ public abstract class StatefulObject extends Namespaced { * Writes the binary representation of the state of this object to the * {@code output}. * - * @param output a {@link DataOutput} that a state can be written to - * @param context the context - * @throws IOException if an error occurs in {@code output} + * @param output + * a {@link DataOutput} that a state can be written to + * @param context + * the context + * @throws IOException + * if an error occurs in {@code output} */ public void write(DataOutput output, IOContext context) throws IOException { getLayout().write(this, output, context); @@ -164,22 +167,19 @@ public abstract class StatefulObject extends Namespaced { * to {@code destination} can affect this object.
    • *
    * - * @param destination the object to copy this object into. + * @param destination + * the object to copy this object into. */ public StatefulObject copy(StatefulObject destination) { Objects.requireNonNull(destination, "destination"); if (destination == this) { - throw new IllegalArgumentException( - "Cannot copy an object into itself" - ); + throw new IllegalArgumentException("Cannot copy an object into itself"); } if (destination.getClass() != this.getClass()) { throw new IllegalArgumentException( - "Cannot copy from " + getClass() - + " (ID " + getId() + ") to " + destination.getClass() - ); + "Cannot copy from " + getClass() + " (ID " + getId() + ") to " + destination.getClass()); } getLayout().copy(this, destination); @@ -200,7 +200,8 @@ public abstract class StatefulObject extends Namespaced { * {@linkplain #isLike(Object) "like"} and their binary representations * match exactly. * - * @param obj the object to examine + * @param obj + * the object to examine * @return {@code true} if {@code obj != null} and this object is equal to * {@code obj} */ @@ -220,7 +221,8 @@ public abstract class StatefulObject extends Namespaced { * Returns {@code true} iff this object and {@code obj} have the same ID and * are instances of the same class. * - * @param obj the object to examine + * @param obj + * the object to examine * @return {@code true} if {@code obj} is "like" this object */ public boolean isLike(Object obj) { diff --git a/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectLayout.java b/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectLayout.java index 4490cdf..b841848 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectLayout.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectLayout.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; import java.io.DataInput; @@ -38,25 +38,13 @@ public abstract class StatefulObjectLayout { protected void checkObject(StatefulObject object) { if (!object.getId().equals(getObjectId())) { - throw new IllegalArgumentException( - object.getId() + " is not " + getObjectId() - ); + throw new IllegalArgumentException(object.getId() + " is not " + getObjectId()); } } - public abstract void read( - StatefulObject object, - DataInput input, - IOContext context - ) - throws IOException; + public abstract void read(StatefulObject object, DataInput input, IOContext context) throws IOException; - public abstract void write( - StatefulObject object, - DataOutput output, - IOContext context - ) - throws IOException; + public abstract void write(StatefulObject object, DataOutput output, IOContext context) throws IOException; public abstract void copy(StatefulObject from, StatefulObject to); diff --git a/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java b/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java index aa082a6..8f01ac8 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.state; import java.util.Collections; @@ -78,9 +78,7 @@ public class StatefulObjectRegistry { StatefulObjectLayout layout = layouts.get(id); if (layout == null) { - throw new IllegalArgumentException( - "ID " + id + " has not been registered" - ); + throw new IllegalArgumentException("ID " + id + " has not been registered"); } return layout; @@ -88,9 +86,7 @@ public class StatefulObjectRegistry { protected void register(Type type) { if (!type.getRegistrationFlag().compareAndSet(false, true)) { - throw new IllegalStateException( - "ID " + type.getId() + " is already registered" - ); + throw new IllegalStateException("ID " + type.getId() + " is already registered"); } InspectingStatefulObjectLayout inspector = new InspectingStatefulObjectLayout(type.getId()); diff --git a/src/main/java/ru/windcorp/progressia/common/util/ArrayFloatRangeMap.java b/src/main/java/ru/windcorp/progressia/common/util/ArrayFloatRangeMap.java new file mode 100644 index 0000000..4eea3f6 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/ArrayFloatRangeMap.java @@ -0,0 +1,225 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.util; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Objects; + +public class ArrayFloatRangeMap implements FloatRangeMap { + + protected static class Node implements Comparable> { + public float pos; + public E value; + + public Node(float pos, E value) { + this.pos = pos; + this.value = value; + } + + @Override + public int compareTo(Node o) { + return Float.compare(pos, o.pos); + } + } + + /* + * Expects a random-access list + */ + protected final List> nodes; + protected int ranges = 0; + + protected static final int DEFAULT_CAPACITY = 16; + + public ArrayFloatRangeMap(int capacity) { + this.nodes = new ArrayList<>(2 * capacity); + } + + public ArrayFloatRangeMap() { + this(DEFAULT_CAPACITY); + } + + @Override + public int size() { + return this.ranges; + } + + @Override + public Iterator iterator() { + return new Iterator() { + + private int nextIndex = 0; + + { + assert nodes.isEmpty() || nodes.get(nextIndex).value != null; + } + + private void findNext() { + while (nextIndex < nodes.size()) { + nextIndex++; + Node node = nodes.get(nextIndex); + if (node.value != null) return; + } + } + + @Override + public boolean hasNext() { + return nextIndex < nodes.size(); + } + + @Override + public E next() { + E result = nodes.get(nextIndex).value; + findNext(); + return result; + } + }; + } + + /** + * Returns an index of the smallest {@link Node} larger than or exactly at + * {@code position}. + * + * @param position the position to look up + * @return an index in the {@link #nodes} list containing the first + * {@link Node} whose {@link Node#pos} is not smaller than + * {@code position}, or {@code nodes.size()} if no such index exists + */ + protected int findCeiling(float position) { + + /* + * Implementation based on OpenJDK's + * Collections.indexedBinarySearch(List, Comparator) + */ + + int low = 0; + int high = nodes.size() - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + float midVal = nodes.get(mid).pos; + int cmp = Float.compare(midVal, position); + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + + return low; // the insertion point is the desired index + } + + /** + * Returns an index of the largest {@link Node} smaller than or exactly at + * {@code position}. + * + * @param position the position to look up + * @return an index in the {@link #nodes} list containing the last + * {@link Node} whose {@link Node#pos} is not greater than + * {@code position}, or {@code -1} if no such index exists + */ + protected int findFloor(float position) { + + /* + * Implementation based on OpenJDK's + * Collections.indexedBinarySearch(List, Comparator) + */ + + int low = 0; + int high = nodes.size() - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + float midVal = nodes.get(mid).pos; + int cmp = Float.compare(midVal, position); + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + + return low - 1; // the insertion point immediately follows the desired index + } + + protected Node getEffectiveNode(float at) { + int effectiveNodeIndex = findFloor(at); + if (effectiveNodeIndex < 0) return null; + return nodes.get(effectiveNodeIndex); + } + + @Override + public E get(float at) { + Node effectiveNode = getEffectiveNode(at); + return effectiveNode == null ? null : effectiveNode.value; + } + + @Override + public void put(float min, float max, E element) { + Objects.requireNonNull(element, "element"); + + if (!(max > min)) // This funky construction also deals with NaNs since NaNs always fail any comparison + { + throw new IllegalArgumentException(max + " is not greater than " + min); + } + + int indexOfInsertionOfMin = findCeiling(min); + + nodes.add(indexOfInsertionOfMin, new Node(min, element)); + ranges++; + + ListIterator> it = nodes.listIterator(indexOfInsertionOfMin + 1); + E elementEffectiveImmediatelyAfterInsertedRange = null; + + if (indexOfInsertionOfMin > 0) { + elementEffectiveImmediatelyAfterInsertedRange = nodes.get(indexOfInsertionOfMin - 1).value; + } + + while (it.hasNext()) { + Node node = it.next(); + + if (node.pos >= max) { + break; + } + + elementEffectiveImmediatelyAfterInsertedRange = node.value; + if (elementEffectiveImmediatelyAfterInsertedRange != null) { + // Removing an actual range + ranges--; + } + it.remove(); + } + + if (max != Float.POSITIVE_INFINITY) { + nodes.add(indexOfInsertionOfMin + 1, new Node(max, elementEffectiveImmediatelyAfterInsertedRange)); + + if (elementEffectiveImmediatelyAfterInsertedRange != null) { + // We might have added one right back + ranges++; + } + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/BinUtil.java b/src/main/java/ru/windcorp/progressia/common/util/BinUtil.java index ffc8a43..042d2a1 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/BinUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/BinUtil.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; public class BinUtil { diff --git a/src/main/java/ru/windcorp/progressia/common/util/ByteBufferInputStream.java b/src/main/java/ru/windcorp/progressia/common/util/ByteBufferInputStream.java index 6b317a7..f3380a9 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/ByteBufferInputStream.java +++ b/src/main/java/ru/windcorp/progressia/common/util/ByteBufferInputStream.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import java.io.InputStream; diff --git a/src/main/java/ru/windcorp/progressia/common/util/ByteBufferOutputStream.java b/src/main/java/ru/windcorp/progressia/common/util/ByteBufferOutputStream.java index 8931c75..152a17f 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/ByteBufferOutputStream.java +++ b/src/main/java/ru/windcorp/progressia/common/util/ByteBufferOutputStream.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import java.io.IOException; diff --git a/src/main/java/ru/windcorp/progressia/common/util/CoordinatePacker.java b/src/main/java/ru/windcorp/progressia/common/util/CoordinatePacker.java index 0ef2413..f909b8a 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/CoordinatePacker.java +++ b/src/main/java/ru/windcorp/progressia/common/util/CoordinatePacker.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import glm.vec._2.i.Vec2i; @@ -33,13 +33,10 @@ public class CoordinatePacker { BITS_3_INTS_INTO_LONG = 64 / 3; /* - * What happens below: - * 1. 1 << BITS_3_INTS_INTO_LONG: - * 0000 ... 00100 ... 0000 - * \_________/ - BITS_3_INTS_INTO_LONG zeros - * 2. (1 << BITS_3_INTS_INTO_LONG) - 1: - * 0000 ... 00011 ... 1111 - * \_________/ - BITS_3_INTS_INTO_LONG ones - WIN + * What happens below: 1. 1 << BITS_3_INTS_INTO_LONG: 0000 ... 00100 ... + * 0000 \_________/ - BITS_3_INTS_INTO_LONG zeros 2. (1 << + * BITS_3_INTS_INTO_LONG) - 1: 0000 ... 00011 ... 1111 \_________/ - + * BITS_3_INTS_INTO_LONG ones - WIN */ MASK_3_INTS_INTO_LONG = (1l << BITS_3_INTS_INTO_LONG) - 1; @@ -49,9 +46,9 @@ public class CoordinatePacker { } public static long pack3IntsIntoLong(int a, int b, int c) { - return ((a & MASK_3_INTS_INTO_LONG) << (2 * BITS_3_INTS_INTO_LONG)) | - ((b & MASK_3_INTS_INTO_LONG) << (1 * BITS_3_INTS_INTO_LONG)) | - ((c & MASK_3_INTS_INTO_LONG) << (0 * BITS_3_INTS_INTO_LONG)); + return ((a & MASK_3_INTS_INTO_LONG) << (2 * BITS_3_INTS_INTO_LONG)) + | ((b & MASK_3_INTS_INTO_LONG) << (1 * BITS_3_INTS_INTO_LONG)) + | ((c & MASK_3_INTS_INTO_LONG) << (0 * BITS_3_INTS_INTO_LONG)); } public static long pack3IntsIntoLong(Vec3i v) { @@ -63,8 +60,7 @@ public class CoordinatePacker { throw new IllegalArgumentException("Invalid index " + index); } - int result = (int) ((packed >>> ((2 - index) * BITS_3_INTS_INTO_LONG)) - & MASK_3_INTS_INTO_LONG); + int result = (int) ((packed >>> ((2 - index) * BITS_3_INTS_INTO_LONG)) & MASK_3_INTS_INTO_LONG); final long signMask = ((MASK_3_INTS_INTO_LONG + 1) >> 1); @@ -79,18 +75,14 @@ public class CoordinatePacker { if (output == null) output = new Vec3i(); - output.set( - unpack3IntsFromLong(packed, 0), - unpack3IntsFromLong(packed, 1), - unpack3IntsFromLong(packed, 2) - ); + output.set(unpack3IntsFromLong(packed, 0), unpack3IntsFromLong(packed, 1), unpack3IntsFromLong(packed, 2)); return output; } public static long pack2IntsIntoLong(int a, int b) { - return ((a & MASK_2_INTS_INTO_LONG) << (1 * BITS_2_INTS_INTO_LONG)) | - ((b & MASK_2_INTS_INTO_LONG) << (0 * BITS_2_INTS_INTO_LONG)); + return ((a & MASK_2_INTS_INTO_LONG) << (1 * BITS_2_INTS_INTO_LONG)) + | ((b & MASK_2_INTS_INTO_LONG) << (0 * BITS_2_INTS_INTO_LONG)); } public static long pack2IntsIntoLong(Vec2i v) { @@ -102,8 +94,7 @@ public class CoordinatePacker { throw new IllegalArgumentException("Invalid index " + index); } - int result = (int) ((packed >>> ((1 - index) * BITS_2_INTS_INTO_LONG)) - & MASK_2_INTS_INTO_LONG); + int result = (int) ((packed >>> ((1 - index) * BITS_2_INTS_INTO_LONG)) & MASK_2_INTS_INTO_LONG); return result; } @@ -112,10 +103,7 @@ public class CoordinatePacker { if (output == null) output = new Vec2i(); - output.set( - unpack2IntsFromLong(packed, 0), - unpack2IntsFromLong(packed, 1) - ); + output.set(unpack2IntsFromLong(packed, 0), unpack2IntsFromLong(packed, 1)); return output; } diff --git a/src/main/java/ru/windcorp/progressia/common/util/DataBuffer.java b/src/main/java/ru/windcorp/progressia/common/util/DataBuffer.java index 23522c1..b500ace 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/DataBuffer.java +++ b/src/main/java/ru/windcorp/progressia/common/util/DataBuffer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import java.io.DataInput; @@ -113,10 +113,7 @@ public class DataBuffer { int length = buffer.size(); while (position < length) { - int currentLength = Math.min( - transferBuffer.length, - length - position - ); + int currentLength = Math.min(transferBuffer.length, length - position); buffer.toArray(transferBuffer, position, 0, currentLength); sink.write(transferBuffer, 0, currentLength); diff --git a/src/main/java/ru/windcorp/progressia/common/util/FloatMathUtil.java b/src/main/java/ru/windcorp/progressia/common/util/FloatMathUtil.java index 43487c0..a1008de 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/FloatMathUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/FloatMathUtil.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; public class FloatMathUtil { diff --git a/src/main/java/ru/windcorp/progressia/common/util/FloatRangeMap.java b/src/main/java/ru/windcorp/progressia/common/util/FloatRangeMap.java new file mode 100644 index 0000000..303d6a8 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/FloatRangeMap.java @@ -0,0 +1,36 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.util; + +public interface FloatRangeMap extends Iterable { + + void put(float min, float max, E element); + E get(float at); + + int size(); + + default boolean defines(float position) { + return get(position) != null; + } + + default E getOrDefault(float at, E def) { + E result = get(at); + return result == null ? def : result; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java b/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java index c5b2952..9d668e9 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java +++ b/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import java.util.ArrayList; diff --git a/src/main/java/ru/windcorp/progressia/common/util/Matrices.java b/src/main/java/ru/windcorp/progressia/common/util/Matrices.java index 8804272..b36669b 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/Matrices.java +++ b/src/main/java/ru/windcorp/progressia/common/util/Matrices.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import glm.mat._3.Mat3; @@ -37,8 +37,8 @@ import glm.mat._4.d.Mat4d; * } * * - * Provided objects may be reused after {@code release} has been invoked; - * do not store them. + * Provided objects may be reused after {@code release} has been invoked; do not + * store them. *

    * This class is thread- and recursion-safe. * diff --git a/src/main/java/ru/windcorp/progressia/common/util/MultiLOC.java b/src/main/java/ru/windcorp/progressia/common/util/MultiLOC.java index 295244d..3d417ac 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/MultiLOC.java +++ b/src/main/java/ru/windcorp/progressia/common/util/MultiLOC.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import java.util.HashMap; diff --git a/src/main/java/ru/windcorp/progressia/common/util/Named.java b/src/main/java/ru/windcorp/progressia/common/util/Named.java index d9fc97a..8722ad4 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/Named.java +++ b/src/main/java/ru/windcorp/progressia/common/util/Named.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import java.util.Objects; diff --git a/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java b/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java index 2010ccb..9e86954 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java +++ b/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import java.util.Collection; @@ -27,9 +27,7 @@ import com.google.common.collect.ForwardingList; public class SizeLimitedList extends ForwardingList { - private static final class RandomAccessSizeLimitedList - extends SizeLimitedList - implements RandomAccess { + private static final class RandomAccessSizeLimitedList extends SizeLimitedList implements RandomAccess { protected RandomAccessSizeLimitedList(List parent, int maxSize) { super(parent, maxSize); } @@ -76,9 +74,7 @@ public class SizeLimitedList extends ForwardingList { private void checkMaxSize() { if (size() >= maxSize) { - throw new UnsupportedOperationException( - "Maximum size " + maxSize + " reached" - ); + throw new UnsupportedOperationException("Maximum size " + maxSize + " reached"); } } diff --git a/src/main/java/ru/windcorp/progressia/common/util/StashingStack.java b/src/main/java/ru/windcorp/progressia/common/util/StashingStack.java index 394c79d..fcd4059 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/StashingStack.java +++ b/src/main/java/ru/windcorp/progressia/common/util/StashingStack.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import java.util.Arrays; @@ -45,9 +45,8 @@ public class StashingStack implements Iterable { /** * Stores all elements. Elements with indices - * [0; {@link #head}] - * are present in the stack, elements with indices - * ({@link #head}; contents.length] are stashed. + * [0; {@link #head}] are present in the stack, elements with + * indices ({@link #head}; contents.length] are stashed. */ private final Object[] contents; @@ -66,7 +65,8 @@ public class StashingStack implements Iterable { /** * Creates a new stack. Its stash is filled with {@code null}s. * - * @param capacity stack's capacity + * @param capacity + * stack's capacity */ public StashingStack(int capacity) { this((T[]) new Object[capacity], 0); @@ -75,7 +75,8 @@ public class StashingStack implements Iterable { /** * Creates a new stack with the supplied stash. * - * @param contents elements that are put in the stash initially. + * @param contents + * elements that are put in the stash initially. */ public StashingStack(T[] contents) { this(contents.clone(), 0); @@ -84,7 +85,8 @@ public class StashingStack implements Iterable { /** * Creates a new stack with the supplied stash. * - * @param contents elements that are put in the stash initially. + * @param contents + * elements that are put in the stash initially. */ public StashingStack(Iterable contents) { this(Iterables.toArray(contents, Object.class), 0); @@ -95,8 +97,10 @@ public class StashingStack implements Iterable { * {@code generator}. The generator's {@link Supplier#get() get()} method * will only be invoked {@code capacity} times from within this constructor. * - * @param capacity stack's capacity - * @param generator a supplier of objects for the stash + * @param capacity + * stack's capacity + * @param generator + * a supplier of objects for the stash */ public StashingStack(int capacity, Supplier generator) { this(capacity); @@ -160,7 +164,8 @@ public class StashingStack implements Iterable { * empty throws a {@link NoSuchElementException}. * * @return head of this stack - * @throws NoSuchElementException is the stack is empty + * @throws NoSuchElementException + * is the stack is empty * @see #peek() */ public T getHead() { @@ -170,8 +175,8 @@ public class StashingStack implements Iterable { } /** - * Returns and removes the head of this stack. If the stack is - * empty returns {@code null}. + * Returns and removes the head of this stack. If the stack is empty returns + * {@code null}. * * @return head of this stack or {@code null} * @see #removeHead() @@ -183,11 +188,12 @@ public class StashingStack implements Iterable { } /** - * Returns and removes the head of this stack. If the stack is - * empty throws a {@link NoSuchElementException}. + * Returns and removes the head of this stack. If the stack is empty throws + * a {@link NoSuchElementException}. * * @return head of this stack - * @throws NoSuchElementException is the stack is empty + * @throws NoSuchElementException + * is the stack is empty * @see #pop() */ public T removeHead() { @@ -216,7 +222,8 @@ public class StashingStack implements Iterable { * removed. If the stack is already full throws an * {@link IllegalStateException}. * - * @param newElement the element to push + * @param newElement + * the element to push * @return the new head */ public T push(T newElement) { @@ -233,17 +240,16 @@ public class StashingStack implements Iterable { * bottom of the stack. If the index is out of bounds, an * {@link IndexOutOfBoundsException} is thrown. * - * @param index index of the element to retrieve, - * [0; {@link #getSize()}) + * @param index + * index of the element to retrieve, + * [0; {@link #getSize()}) * @return the requested element - * @throws IndexOutOfBoundsException if the index is negative or greater - * than head + * @throws IndexOutOfBoundsException + * if the index is negative or greater than head */ public T get(int index) { if (index > head) { - throw new IndexOutOfBoundsException( - "Requested index " + index + " > head " + head - ); + throw new IndexOutOfBoundsException("Requested index " + index + " > head " + head); } return (T) contents[index]; diff --git a/src/main/java/ru/windcorp/progressia/common/util/TaskQueue.java b/src/main/java/ru/windcorp/progressia/common/util/TaskQueue.java index a081356..7010896 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/TaskQueue.java +++ b/src/main/java/ru/windcorp/progressia/common/util/TaskQueue.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import java.util.Collection; @@ -62,11 +62,7 @@ public class TaskQueue { private final Object waitAndInvokeMonitor = new Object(); @SuppressWarnings("unchecked") - public void waitAndInvoke( - ThrowingRunnable task - ) - throws InterruptedException, - E { + public void waitAndInvoke(ThrowingRunnable task) throws InterruptedException, E { if (runNow.getAsBoolean()) { task.run(); diff --git a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java index 00ede3e..f25368f 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java @@ -20,6 +20,8 @@ package ru.windcorp.progressia.common.util; import java.util.function.Consumer; +import glm.Glm; +import glm.mat._3.Mat3; import glm.mat._4.Mat4; import glm.vec._2.Vec2; import glm.vec._2.d.Vec2d; @@ -36,6 +38,40 @@ public class VectorUtil { public static enum Axis { X, Y, Z, W; } + + public static enum SignedAxis { + POS_X(Axis.X, +1), + NEG_X(Axis.X, -1), + POS_Y(Axis.Y, +1), + NEG_Y(Axis.Y, -1), + POS_Z(Axis.Z, +1), + NEG_Z(Axis.Z, -1), + POS_W(Axis.W, +1), + NEG_W(Axis.W, -1); + + private final Axis axis; + private final boolean isPositive; + + private SignedAxis(Axis axis, int sign) { + this.axis = axis; + this.isPositive = (sign == +1 ? true : false); + } + + /** + * @return the axis + */ + public Axis getAxis() { + return axis; + } + + public boolean isPositive() { + return isPositive; + } + + public int getSign() { + return isPositive ? +1 : -1; + } + } public static void iterateCuboid( int x0, @@ -124,7 +160,11 @@ public class VectorUtil { iterateCuboidAround(center.x, center.y, center.z, diameter, action); } - public static void applyMat4(Vec3 in, Mat4 mat, Vec3 out) { + public static Vec3 applyMat4(Vec3 in, Mat4 mat, Vec3 out) { + if (out == null) { + out = new Vec3(); + } + Vec4 vec4 = Vectors.grab4(); vec4.set(in, 1f); @@ -132,15 +172,83 @@ public class VectorUtil { out.set(vec4.x, vec4.y, vec4.z); Vectors.release(vec4); + + return out; } - public static void applyMat4(Vec3 inOut, Mat4 mat) { - Vec4 vec4 = Vectors.grab4(); - vec4.set(inOut, 1f); - - mat.mul(vec4); - - inOut.set(vec4.x, vec4.y, vec4.z); + public static Vec3 applyMat4(Vec3 inOut, Mat4 mat) { + return applyMat4(inOut, mat, inOut); + } + + public static Vec3 rotate(Vec3 in, Vec3 axis, float angle, Vec3 out) { + if (out == null) { + out = new Vec3(); + } + + Mat3 mat = Matrices.grab3(); + + mat.identity().rotate(angle, axis); + mat.mul(in, out); + + Matrices.release(mat); + + return out; + } + + public static Vec3 rotate(Vec3 inOut, Vec3 axis, float angle) { + return rotate(inOut, axis, angle, inOut); + } + + public static double getAngle(Vec3 from, Vec3 to, Vec3 normal) { + Vec3 left = Vectors.grab3(); + + left.set(normal).cross(from); + double sign = Math.signum(left.dot(to)); + + double result = (float) Math.acos(Glm.clamp(from.dot(to), -1, +1)) * sign; + + Vectors.release(left); + return result; + } + + public static Vec3 projectOnSurface(Vec3 in, Vec3 normal, Vec3 out) { + if (in == out) { + return projectOnSurface(in, normal); + } + + if (out == null) { + out = new Vec3(); + } + + out.set(normal).mul(-normal.dot(in)).add(in); + + return out; + } + + public static Vec3 projectOnSurface(Vec3 inOut, Vec3 normal) { + Vec3 buffer = Vectors.grab3(); + + projectOnSurface(inOut, normal, buffer); + inOut.set(buffer); + + Vectors.release(buffer); + + return inOut; + } + + public static Vec3 projectOnVector(Vec3 in, Vec3 vector, Vec3 out) { + if (out == null) { + out = new Vec3(); + } + + float dot = vector.dot(in); + out.set(vector).mul(dot); + + return out; + } + + public static Vec3 projectOnVector(Vec3 inOut, Vec3 vector) { + return projectOnVector(inOut, vector); } public static Vec3 linearCombination( @@ -150,6 +258,10 @@ public class VectorUtil { float kb, Vec3 output ) { + if (output == null) { + output = new Vec3(); + } + output.set( va.x * ka + vb.x * kb, va.y * ka + vb.y * kb, @@ -167,6 +279,10 @@ public class VectorUtil { float kc, Vec3 output ) { + if (output == null) { + output = new Vec3(); + } + output.set( va.x * ka + vb.x * kb + vc.x * kc, va.y * ka + vb.y * kb + vc.y * kc, @@ -174,6 +290,88 @@ public class VectorUtil { ); return output; } + + public static Vec3i sort(Vec3i input, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + int ax = input.x, ay = input.y, az = input.z; + + if (ax > ay) { + if (ax > az) { + output.x = ax; + output.y = ay > az ? ay : az; + output.z = ay > az ? az : ay; + } else { + output.x = az; + output.y = ax; + output.z = ay; + } + } else { + if (ay > az) { + output.x = ay; + output.y = ax > az ? ax : az; + output.z = ax > az ? az : ax; + } else { + output.x = az; + output.y = ay; + output.z = ax; + } + } + + return output; + } + + public static Vec3 sort(Vec3 input, Vec3 output) { + if (output == null) { + output = new Vec3(); + } + + float ax = input.x, ay = input.y, az = input.z; + + if (ax > ay) { + if (ax > az) { + output.x = ax; + output.y = ay > az ? ay : az; + output.z = ay > az ? az : ay; + } else { + output.x = az; + output.y = ax; + output.z = ay; + } + } else { + if (ay > az) { + output.x = ay; + output.y = ax > az ? ax : az; + output.z = ax > az ? az : ax; + } else { + output.x = az; + output.y = ay; + output.z = ax; + } + } + + return output; + } + + public static Vec3i sortAfterAbs(Vec3i input, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + input.abs(output); + return sort(output, output); + } + + public static Vec3 sortAfterAbs(Vec3 input, Vec3 output) { + if (output == null) { + output = new Vec3(); + } + + input.abs(output); + return sort(output, output); + } public static float get(Vec2 v, Axis a) { switch (a) { diff --git a/src/main/java/ru/windcorp/progressia/common/util/Vectors.java b/src/main/java/ru/windcorp/progressia/common/util/Vectors.java index 7d99ea5..2cb4336 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/Vectors.java +++ b/src/main/java/ru/windcorp/progressia/common/util/Vectors.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util; import glm.vec._2.Vec2; @@ -40,8 +40,8 @@ import glm.vec._4.i.Vec4i; * } * * - * Provided objects may be reused after {@code release} has been invoked; - * do not store them. + * Provided objects may be reused after {@code release} has been invoked; do not + * store them. *

    * This class is thread- and recursion-safe. * diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java b/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java index 3289c3d..e17f964 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java @@ -15,16 +15,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash; /** * A crash report utility that performs analysis of a problem during crash * report generation and presents its conclusion to the user via the crash - * report. - * Unlike {@link ContextProvider}s, Analyzers are provided with the reported - * problem - * details. + * report. Unlike {@link ContextProvider}s, Analyzers are provided with the + * reported problem details. * * @see ContextProvider * @author serega404 @@ -32,22 +30,24 @@ package ru.windcorp.progressia.common.util.crash; public interface Analyzer { /** - * Provides a human-readable string describing this analyzer's conclusion - * on the presented problem, or returns {@code null} if no conclusion - * could be made. + * Provides a human-readable string describing this analyzer's conclusion on + * the presented problem, or returns {@code null} if no conclusion could be + * made. * - * @param throwable The reported throwable (may be {@code null}) - * @param messageFormat A {@linkplain java.util.Formatter#syntax format - * string} of a - * human-readable description of the problem - * @param args The arguments for the format string + * @param throwable + * The reported throwable (may be {@code null}) + * @param messageFormat + * A {@linkplain java.util.Formatter#syntax format string} of a + * human-readable description of the problem + * @param args + * The arguments for the format string * @return a conclusion or {@code null} */ String analyze(Throwable throwable, String messageFormat, Object... args); /** - * Returns this analyzer's human-readable name. - * It should be A String In Title Case With Spaces. + * Returns this analyzer's human-readable name. It should be A String In + * Title Case With Spaces. * * @return this analyzer's name */ diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java index 5b62663..8180e4a 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash; import java.util.Map; @@ -33,23 +33,20 @@ public interface ContextProvider { /** * Provides human-readable description of the state of the game and the - * system. - * This information is {@link Map#put(Object, Object) put} into the provided - * map - * as key-value pairs. Keys are the characteristic being described, such as - * "OS Name", - * and should be Strings In Title Case With Spaces. - * If this provider cannot provide any information at this moment, the map - * is not - * modified. + * system. This information is {@link Map#put(Object, Object) put} into the + * provided map as key-value pairs. Keys are the characteristic being + * described, such as "OS Name", and should be Strings In Title Case With + * Spaces. If this provider cannot provide any information at this moment, + * the map is not modified. * - * @param output the map to append output to + * @param output + * the map to append output to */ void provideContext(Map output); /** - * Returns this provider's human-readable name. - * It should be A String In Title Case With Spaces. + * Returns this provider's human-readable name. It should be A String In + * Title Case With Spaces. * * @return this provider's name */ diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReports.java b/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReports.java index ab0ec3e..3b634cf 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReports.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReports.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash; import org.apache.logging.log4j.LogManager; @@ -38,9 +38,8 @@ import java.util.*; /** * A utility for reporting critical problems, gathering system context and - * terminating the application consequently (crashing). - * Do not hesitate to use {@link #report(Throwable, String, Object...)} at every - * other line. + * terminating the application consequently (crashing). Do not hesitate to use + * {@link #report(Throwable, String, Object...)} at every other line. * * @author serega404 */ @@ -56,8 +55,8 @@ public class CrashReports { /** * Creates a {@link ReportedException} that describes the provided problem - * so the program can crash later. - * This method is intended to be used like so: + * so the program can crash later. This method is intended to be used like + * so: * *

     	 * try {
    @@ -68,26 +67,24 @@ public class CrashReports {
     	 * 
    *

    * Such usage ensures that the report will be dealt with at the top of the - * call stack - * (at least in methods that have a properly set up + * call stack (at least in methods that have a properly set up * {@linkplain #crash(Throwable, String, Object...) crash handler}). Not - * throwing the returned - * exception is pointless; using this in a thread without a crash handler - * will not produce a crash. + * throwing the returned exception is pointless; using this in a thread + * without a crash handler will not produce a crash. *

    * Avoid inserting variable information into {@code messageFormat} directly; - * use - * {@linkplain Formatter#summary format string} syntax and {@code args}. - * Different Strings - * in {@code messageFormat} may be interpreted as unrelated problems by - * {@linkplain Analyzer crash analyzers}. + * use {@linkplain Formatter#summary format string} syntax and {@code args}. + * Different Strings in {@code messageFormat} may be interpreted as + * unrelated problems by {@linkplain Analyzer crash analyzers}. * - * @param throwable a {@link Throwable} that caused the problem, if any; - * {@code null} otherwise - * @param messageFormat a human-readable description of the problem - * displayed in the crash report - * @param args an array of arguments for formatting - * {@code messageFormat} + * @param throwable + * a {@link Throwable} that caused the problem, if any; + * {@code null} otherwise + * @param messageFormat + * a human-readable description of the problem displayed in the + * crash report + * @param args + * an array of arguments for formatting {@code messageFormat} * @return an exception containing the provided information that must be * thrown */ @@ -102,32 +99,28 @@ public class CrashReports { * Crashes the program due to the supplied problem. *

    * Use {@link #report(Throwable, String, Object...)} unless you are - * creating a catch-all handler for a - * thread. + * creating a catch-all handler for a thread. *

    * This method recovers information about the problem by casting - * {@code throwable} to {@link ReportedException}, - * or, failing that, uses the provided arguments as the information instead. - * It then constructs a full crash - * report, exports it and terminates the program by invoking + * {@code throwable} to {@link ReportedException}, or, failing that, uses + * the provided arguments as the information instead. It then constructs a + * full crash report, exports it and terminates the program by invoking * {@link System#exit(int)}. *

    * Such behavior can be dangerous or lead to unwanted consequences in the - * middle of the call stack, so it is - * necessary to invoke this method as high on the call stack as possible, - * usually in a {@code catch} clause - * of a {@code try} statement enveloping the thread's main method(s). + * middle of the call stack, so it is necessary to invoke this method as + * high on the call stack as possible, usually in a {@code catch} clause of + * a {@code try} statement enveloping the thread's main method(s). * - * @param throwable a {@link ReportedException} or another - * {@link Throwable} that caused the problem, if any; - * {@code null} otherwise - * @param messageFormat a human-readable description of the problem used - * when {@code throwable} is not a - * {@link ReportedException}. See - * {@link #report(Throwable, String, Object...)} for - * details. - * @param args an array of arguments for formatting - * {@code messageFormat} + * @param throwable + * a {@link ReportedException} or another {@link Throwable} that + * caused the problem, if any; {@code null} otherwise + * @param messageFormat + * a human-readable description of the problem used when + * {@code throwable} is not a {@link ReportedException}. See + * {@link #report(Throwable, String, Object...)} for details. + * @param args + * an array of arguments for formatting {@code messageFormat} * @return {@code null}, although this method never returns normally. * Provided for convenience. */ @@ -229,12 +222,8 @@ public class CrashReports { } } - private static boolean appendAnalyzers( - StringBuilder output, - Throwable throwable, - String messageFormat, - Object[] args - ) { + private static boolean appendAnalyzers(StringBuilder output, Throwable throwable, String messageFormat, + Object[] args) { boolean analyzerResponsesExist = false; // Do a local copy to avoid deadlocks -OLEGSHA @@ -334,10 +323,8 @@ public class CrashReports { Files.createDirectory(CRASH_REPORTS_PATH); createFileForCrashReport(output, CRASH_REPORTS_PATH.toString() + "/latest.log"); - createFileForCrashReport( - output, - CRASH_REPORTS_PATH.toString() + "/crash-" + dateFormat.format(date) + ".log" - ); + createFileForCrashReport(output, + CRASH_REPORTS_PATH.toString() + "/crash-" + dateFormat.format(date) + ".log"); } catch (Throwable t) { // Crash Report not created } @@ -359,7 +346,8 @@ public class CrashReports { * Registers the provided {@link ContextProvider} so it is consulted in the * case of a crash. * - * @param provider the provider to register + * @param provider + * the provider to register */ public static void registerProvider(ContextProvider provider) { PROVIDERS.add(provider); @@ -369,7 +357,8 @@ public class CrashReports { * Registers the provided {@link Analyzer} so it is consulted in the case of * a crash. * - * @param analyzer the analyzer to register + * @param analyzer + * the analyzer to register */ public static void registerAnalyzer(Analyzer analyzer) { ANALYZERS.add(analyzer); @@ -377,11 +366,10 @@ public class CrashReports { /** * A wrapper used by {@link CrashReports} to transfer problem details from - * the place of - * occurrence to the handler at the top of the stack. Rethrow if caught - * (unless using {@link CrashReports#report(Throwable, String, Object...)}, - * which does - * so automatically). + * the place of occurrence to the handler at the top of the stack. Rethrow + * if caught (unless using + * {@link CrashReports#report(Throwable, String, Object...)}, which does so + * automatically). * * @author serega404 */ @@ -395,11 +383,13 @@ public class CrashReports { /** * Constructs a {@link ReportedException}. * - * @param throwable the reported {@link Throwable} or {@code null} - * @param messageFormat the reported message format. - * This is not the message of the constructed - * Exception. - * @param args the reported message format arguments + * @param throwable + * the reported {@link Throwable} or {@code null} + * @param messageFormat + * the reported message format. This is not the message + * of the constructed Exception. + * @param args + * the reported message format arguments */ public ReportedException(Throwable throwable, String messageFormat, Object... args) { super(throwable); diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java b/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java index 141efa9..4644afa 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java @@ -15,27 +15,40 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash; import com.google.common.eventbus.EventBus; import ru.windcorp.progressia.common.hacks.GuavaEventBusHijacker; +/** + * A utility for creating Guava's {@link EventBus}es that + * {@linkplain CrashReports report} exceptions instead of suppressing them. + * + * @author javapony + */ public class ReportingEventBus { private ReportingEventBus() { } + /** + * Instantiates a new {@link EventBus} with the provided identifier that + * reports any unhandled exceptions with {@link CrashReports}. + * + * @param identifier the identifier of the new bus + * @return the created event bus + * @implNote This implementation relies on {@link GuavaEventBusHijacker} for + * creating buses with custom identifiers and uncaught exception + * handlers. It may break suddenly with a Guava update. + */ public static EventBus create(String identifier) { - return GuavaEventBusHijacker.newEventBus( - identifier, - (throwable, context) -> { - // Makes sense to append identifier to messageFormat because - // different EventBuses are completely unrelated - throw CrashReports.crash(throwable, "Unexpected exception in EventBus " + identifier); - } - ); + return GuavaEventBusHijacker.newEventBus(identifier, (throwable, context) -> { + // Makes sense to append identifier to messageFormat because + // different EventBuses are completely unrelated + throw CrashReports.crash(throwable, "Unexpected exception in EventBus " + identifier); + }); } } diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java b/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java index c07152f..647e9b3 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash.analyzers; import ru.windcorp.progressia.common.util.crash.Analyzer; diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/ArgsContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/ArgsContextProvider.java index 6c16902..55786c5 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/ArgsContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/ArgsContextProvider.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.ProgressiaLauncher; diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/JavaVersionContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/JavaVersionContextProvider.java index b8f4358..184a916 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/JavaVersionContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/JavaVersionContextProvider.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.common.util.crash.ContextProvider; diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/LanguageContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/LanguageContextProvider.java index ca9d387..8de2668 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/LanguageContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/LanguageContextProvider.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.client.localization.Localizer; diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java index 7fd4610..56752fd 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.common.util.crash.ContextProvider; diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OpenALContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OpenALContextProvider.java index ad31bba..77626b3 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OpenALContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OpenALContextProvider.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.client.audio.AudioManager; diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/RAMContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/RAMContextProvider.java index 9c60921..47e9dd5 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/RAMContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/RAMContextProvider.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.common.util.crash.ContextProvider; @@ -29,11 +29,8 @@ public class RAMContextProvider implements ContextProvider { output.put("Max Memory", Runtime.getRuntime().maxMemory() / 1024 / 1024 + " MB"); output.put("Total Memory", Runtime.getRuntime().totalMemory() / 1024 / 1024 + " MB"); output.put("Free Memory", Runtime.getRuntime().freeMemory() / 1024 / 1024 + " MB"); - output.put( - "Used Memory", - (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024 - + " MB" - ); + output.put("Used Memory", + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024 + " MB"); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DoubleFlusher.java b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DoubleFlusher.java index 6068669..ab21b4b 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DoubleFlusher.java +++ b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DoubleFlusher.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.dynstr; import gnu.trove.list.TCharList; diff --git a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicString.java b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicString.java index 8376a3d..89892c1 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicString.java +++ b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicString.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.dynstr; import java.util.function.Supplier; @@ -45,8 +45,8 @@ public final class DynamicString implements CharSequence { } /** - * Causes the contents of this string to be reevaluated. - * This is not currently thread-safe, take caution. + * Causes the contents of this string to be reevaluated. This is not + * currently thread-safe, take caution. */ public void update() { chars.clear(); diff --git a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicStrings.java b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicStrings.java index 030cd9d..0b5745e 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicStrings.java +++ b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicStrings.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.dynstr; import java.util.ArrayList; diff --git a/src/main/java/ru/windcorp/progressia/common/util/dynstr/FloatFlusher.java b/src/main/java/ru/windcorp/progressia/common/util/dynstr/FloatFlusher.java index 0b245ee..26a727e 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/dynstr/FloatFlusher.java +++ b/src/main/java/ru/windcorp/progressia/common/util/dynstr/FloatFlusher.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.dynstr; import gnu.trove.list.TCharList; diff --git a/src/main/java/ru/windcorp/progressia/common/util/dynstr/IntFlusher.java b/src/main/java/ru/windcorp/progressia/common/util/dynstr/IntFlusher.java index 9924f81..937c9fa 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/dynstr/IntFlusher.java +++ b/src/main/java/ru/windcorp/progressia/common/util/dynstr/IntFlusher.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.dynstr; import gnu.trove.list.TCharList; @@ -61,211 +61,19 @@ class IntFlusher { /* * Copied from OpenJDK's Integer.DigitTens and Integer.DigitOnes */ - private static final char[] DIGIT_TENS = { - '0', - '0', - '0', - '0', - '0', - '0', - '0', - '0', - '0', - '0', - '1', - '1', - '1', - '1', - '1', - '1', - '1', - '1', - '1', - '1', - '2', - '2', - '2', - '2', - '2', - '2', - '2', - '2', - '2', - '2', - '3', - '3', - '3', - '3', - '3', - '3', - '3', - '3', - '3', - '3', - '4', - '4', - '4', - '4', - '4', - '4', - '4', - '4', - '4', - '4', - '5', - '5', - '5', - '5', - '5', - '5', - '5', - '5', - '5', - '5', - '6', - '6', - '6', - '6', - '6', - '6', - '6', - '6', - '6', - '6', - '7', - '7', - '7', - '7', - '7', - '7', - '7', - '7', - '7', - '7', - '8', - '8', - '8', - '8', - '8', - '8', - '8', - '8', - '8', - '8', - '9', - '9', - '9', - '9', - '9', - '9', - '9', - '9', - '9', - '9', - }; + private static final char[] DIGIT_TENS = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', + '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', + '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', + '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7', '7', '7', '7', '7', '7', '7', + '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', '9', '9', + '9', '9', }; - private static final char[] DIGIT_ONES = { - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - }; + private static final char[] DIGIT_ONES = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', + '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', }; /* * Adapted from OpenJDK's Integer.getChars(int, int, byte[]) diff --git a/src/main/java/ru/windcorp/progressia/common/util/namespaces/IllegalIdException.java b/src/main/java/ru/windcorp/progressia/common/util/namespaces/IllegalIdException.java index d896bac..ba27e4a 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/namespaces/IllegalIdException.java +++ b/src/main/java/ru/windcorp/progressia/common/util/namespaces/IllegalIdException.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.namespaces; public class IllegalIdException extends RuntimeException { @@ -26,12 +26,8 @@ public class IllegalIdException extends RuntimeException { super(); } - protected IllegalIdException( - String message, - Throwable cause, - boolean enableSuppression, - boolean writableStackTrace - ) { + protected IllegalIdException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } diff --git a/src/main/java/ru/windcorp/progressia/common/util/namespaces/Namespaced.java b/src/main/java/ru/windcorp/progressia/common/util/namespaces/Namespaced.java index 2d87007..557804b 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/namespaces/Namespaced.java +++ b/src/main/java/ru/windcorp/progressia/common/util/namespaces/Namespaced.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.namespaces; public abstract class Namespaced { diff --git a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedFactoryRegistry.java b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedFactoryRegistry.java index 2a94593..9f419fd 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedFactoryRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedFactoryRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.namespaces; import java.util.Collection; @@ -28,7 +28,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class NamespacedFactoryRegistry - implements Map> { + implements Map> { @FunctionalInterface public static interface Factory { @@ -86,8 +86,7 @@ public class NamespacedFactoryRegistry E result = factory.build(id); if (!result.getId().equals(id)) { throw new IllegalStateException( - "Requested ID " + id + " but factory " + factory + " returned an object with ID " + result.getId() - ); + "Requested ID " + id + " but factory " + factory + " returned an object with ID " + result.getId()); } return result; } diff --git a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedInstanceRegistry.java b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedInstanceRegistry.java index ce1f3cf..e748fe7 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedInstanceRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedInstanceRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.namespaces; import java.util.Collection; @@ -29,8 +29,7 @@ import org.apache.logging.log4j.Logger; import com.google.errorprone.annotations.DoNotCall; -public class NamespacedInstanceRegistry - implements Map { +public class NamespacedInstanceRegistry implements Map { private final Map backingMap = Collections.synchronizedMap(new HashMap<>()); @@ -87,9 +86,7 @@ public class NamespacedInstanceRegistry @DoNotCall @Deprecated public E put(String key, E value) { - throw new UnsupportedOperationException( - "Use NamespacedInstanceRegistry.register(E)" - ); + throw new UnsupportedOperationException("Use NamespacedInstanceRegistry.register(E)"); } @Override @@ -104,9 +101,7 @@ public class NamespacedInstanceRegistry @DoNotCall @Deprecated public void putAll(Map m) { - throw new UnsupportedOperationException( - "Use NamespacedInstanceRegistry.registerAll(Collection)" - ); + throw new UnsupportedOperationException("Use NamespacedInstanceRegistry.registerAll(Collection)"); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedUtil.java b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedUtil.java index b969b8e..0796c50 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedUtil.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.namespaces; import java.util.Objects; @@ -38,8 +38,8 @@ public class NamespacedUtil { public static final int MIN_NAME_LENGTH = MIN_PART_LENGTH; /* - * This is the definition of the accepted pattern, but the value of - * these constants is not actually consulted in the check* methods. + * This is the definition of the accepted pattern, but the value of these + * constants is not actually consulted in the check* methods. */ private static final String PART_CORE_REGEX = "[A-Z][a-zA-Z0-9]{2," + (MAX_PART_LENGTH - 1) + "}"; private static final String PART_REGEX = "^" + PART_CORE_REGEX + "$"; @@ -75,10 +75,8 @@ public class NamespacedUtil { if (areSeparatorsInvalid) { int separators = StringUtil.count(id, SEPARATOR); throw new IllegalIdException( - "ID \"" + id + "\" is invalid. " - + (separators == 0 ? "No " : "Too many (" + separators + ") ") - + "separators '" + SEPARATOR + "' found, exactly one required" - ); + "ID \"" + id + "\" is invalid. " + (separators == 0 ? "No " : "Too many (" + separators + ") ") + + "separators '" + SEPARATOR + "' found, exactly one required"); } checkPart(id, 0, firstSeparator, "namespace"); @@ -89,32 +87,20 @@ public class NamespacedUtil { Objects.requireNonNull(data, nameForErrors); if (length > MAX_PART_LENGTH) { - throw new IllegalIdException( - nameForErrors + " \"" + data.substring(offset, offset + length) + "\" is too long. " - + "Expected at most " + MAX_PART_LENGTH - + " characters" - ); + throw new IllegalIdException(nameForErrors + " \"" + data.substring(offset, offset + length) + + "\" is too long. " + "Expected at most " + MAX_PART_LENGTH + " characters"); } else if (length < MIN_PART_LENGTH) { - throw new IllegalIdException( - nameForErrors + " \"" + data.substring(offset, offset + length) + "\" is too short. " - + "Expected at lest " + MIN_PART_LENGTH - + " characters" - ); + throw new IllegalIdException(nameForErrors + " \"" + data.substring(offset, offset + length) + + "\" is too short. " + "Expected at lest " + MIN_PART_LENGTH + " characters"); } // Don't actually use *_REGEX for speed for (int i = 0; i < length; ++i) { char c = data.charAt(i + offset); - if ( - !((c >= 'A' && c <= 'Z') || - (i != 0 && c >= 'a' && c <= 'z') || - (i != 0 && c >= '0' && c <= '9')) - ) { - throw new IllegalIdException( - nameForErrors + " \"" + data.substring(offset, offset + length) + "\" is invalid. " - + "Allowed is: " + PART_REGEX - ); + if (!((c >= 'A' && c <= 'Z') || (i != 0 && c >= 'a' && c <= 'z') || (i != 0 && c >= '0' && c <= '9'))) { + throw new IllegalIdException(nameForErrors + " \"" + data.substring(offset, offset + length) + + "\" is invalid. " + "Allowed is: " + PART_REGEX); } } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileReference.java b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/DiscreteNoise.java similarity index 78% rename from src/main/java/ru/windcorp/progressia/common/world/tile/TileReference.java rename to src/main/java/ru/windcorp/progressia/common/util/noise/discrete/DiscreteNoise.java index 75fde58..3e600f0 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileReference.java +++ b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/DiscreteNoise.java @@ -15,19 +15,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -package ru.windcorp.progressia.common.world.tile; +package ru.windcorp.progressia.common.util.noise.discrete; -public interface TileReference { - - TileData get(); - - int getIndex(); - - TileDataStack getStack(); - - default boolean isValid() { - return get() != null; - } +public interface DiscreteNoise { + + T get(double x, double y); + T get(double x, double y, double z); } diff --git a/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/WorleyProceduralNoise.java b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/WorleyProceduralNoise.java new file mode 100644 index 0000000..258e9b0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/WorleyProceduralNoise.java @@ -0,0 +1,228 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.util.noise.discrete; + +import java.util.Collection; +import com.google.common.collect.ImmutableList; + +public class WorleyProceduralNoise implements DiscreteNoise { + + /* + * Stolen from OpenJDK's Random implementation + * *evil cackling* + */ + private static final long MULTIPLIER = 0x5DEECE66DL; + private static final long ADDEND = 0xBL; + private static final long MASK = (1L << 48) - 1; + private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53) + + private static long permute(long seed) { + return (seed * MULTIPLIER + ADDEND) & MASK; + } + + private static double getDouble(long seed) { + final int mask26bits = (1 << 26) - 1; + final int mask27bits = (1 << 27) - 1; + + int randomBitsX26 = (int) (seed & 0xFFFFFFFF); + int randomBitsX27 = (int) ((seed >>> Integer.SIZE) & 0xFFFFFFFF); + + randomBitsX26 = randomBitsX26 & mask26bits; + randomBitsX27 = randomBitsX27 & mask27bits; + + return (((long) (randomBitsX26) << 27) + randomBitsX27) * DOUBLE_UNIT; + } + + public static class Entry { + private final T value; + private final double chance; + + public Entry(T value, double chance) { + this.value = value; + this.chance = chance; + } + } + + public static class Builder { + + com.google.common.collect.ImmutableList.Builder> builder = ImmutableList.builder(); + + public Builder add(T value, double chance) { + builder.add(new Entry<>(value, chance)); + return this; + } + + public WorleyProceduralNoise build(long seed) { + return new WorleyProceduralNoise<>(this, seed); + } + + } + + public static Builder builder() { + return new Builder<>(); + } + + private final Entry[] entries; + private final long seed; + + public WorleyProceduralNoise(Builder builder, long seed) { + this(builder.builder.build(), seed); + } + + public WorleyProceduralNoise(Collection> entries, long seed) { + this.entries = new Entry[entries.size()]; + + double chancesSum = 0; + for (Entry entry : entries) { + chancesSum += entry.chance; + } + + int i = 0; + for (Entry entry : entries) { + this.entries[i] = new Entry(entry.value, entry.chance / chancesSum); + i++; + } + + this.seed = seed; + } + + @Override + public T get(double x, double y) { + + int ox = (int) x; + int oy = (int) y; + + T closest = null; + double closestDistanceSq = Double.POSITIVE_INFINITY; + + for (int cellX = ox - 1; cellX <= ox + 1; ++cellX) { + for (int cellY = oy - 1; cellY <= oy + 1; ++cellY) { + + long cellSeed = permute(cellY ^ permute(cellX ^ seed)); + + int nodes = getNodeCount(cellSeed); + cellSeed = permute(cellSeed); + + for (int i = 0; i < nodes; ++i) { + + double nodeX = getDouble(cellSeed) + cellX; + cellSeed = permute(cellSeed); + + double nodeY = getDouble(cellSeed) + cellY; + cellSeed = permute(cellSeed); + + T value = getValue(getDouble(cellSeed)); + cellSeed = permute(cellSeed); + + double distanceSq = (x - nodeX) * (x - nodeX) + (y - nodeY) * (y - nodeY); + if (distanceSq < closestDistanceSq) { + closestDistanceSq = distanceSq; + closest = value; + } + + } + } + } + + return closest; + + } + + @Override + public T get(double x, double y, double z) { + + int ox = (int) x; + int oy = (int) y; + int oz = (int) z; + + T closest = null; + double closestDistanceSq = Double.POSITIVE_INFINITY; + + for (int cellX = ox - 1; cellX <= ox + 1; ++cellX) { + for (int cellY = oy - 1; cellY <= oy + 1; ++cellY) { + for (int cellZ = oz - 1; cellZ <= oz + 1; ++cellZ) { + + long cellSeed = permute(cellZ ^ permute(cellY ^ permute(cellX ^ seed))); + + int nodes = getNodeCount(cellSeed); + cellSeed = permute(cellSeed); + + for (int i = 0; i < nodes; ++i) { + + double nodeX = getDouble(cellSeed) + cellX; + cellSeed = permute(cellSeed); + + double nodeY = getDouble(cellSeed) + cellY; + cellSeed = permute(cellSeed); + + double nodeZ = getDouble(cellSeed) + cellZ; + cellSeed = permute(cellSeed); + + T value = getValue(getDouble(cellSeed)); + cellSeed = permute(cellSeed); + + double distanceSq = (x - nodeX) * (x - nodeX) + (y - nodeY) * (y - nodeY) + + (z - nodeZ) * (z - nodeZ); + if (distanceSq < closestDistanceSq) { + closestDistanceSq = distanceSq; + closest = value; + } + + } + } + } + } + + return closest; + + } + + @SuppressWarnings("unchecked") + private T getValue(double target) { + int i; + + for (i = 0; i < entries.length && target > entries[i].chance; ++i) { + target -= entries[i].chance; + } + + return (T) entries[i].value; + } + + private int getNodeCount(long seed) { + int uniform = ((int) seed) % 8; + + switch (uniform) { + case 0: + case 1: + case 2: + case 3: + return 1; + + case 4: + case 5: + return 2; + + case 6: + return 3; + + default: + return 4; + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java index 4d5f1f9..c81e1a9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java +++ b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java @@ -15,14 +15,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.VectorUtil.Axis; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import static java.lang.Math.*; @@ -34,14 +34,22 @@ public class BlockRay { private float distance; private final Vec3i block = new Vec3i(); - private BlockFace currentFace = null; + private AbsFace currentFace = null; private boolean isValid = false; public void start(Vec3 position, Vec3 direction) { - if (!direction.any()) { + if (direction.x == 0 && direction.y == 0 && direction.z == 0) { throw new IllegalArgumentException("Direction is a zero vector"); } + + if (Float.isNaN(direction.x) || Float.isNaN(direction.y) || Float.isNaN(direction.z)) { + throw new IllegalArgumentException("Direction contains NaN: " + direction); + } + + if (Float.isNaN(position.x) || Float.isNaN(position.y) || Float.isNaN(position.z)) { + throw new IllegalArgumentException("Position contains NaN: " + position); + } isValid = true; this.position.set(position).sub(0.5f); // Make sure lattice points are @@ -75,16 +83,14 @@ public class BlockRay { tMin = tz; axis = Axis.Z; } + + assert tMin > 0 : "tMin is not positive (" + tMin + ")"; // block.(axis) += signum(direction.(axis)) VectorUtil.set(block, axis, VectorUtil.get(block, axis) + (int) signum(VectorUtil.get(direction, axis))); // position += direction * tMin - VectorUtil.linearCombination(position, 1, direction, tMin, position); // position - // += - // direction - // * - // tMin + VectorUtil.linearCombination(position, 1, direction, tMin, position); distance += tMin; // position.(axis) = round(position.(axis)) @@ -110,18 +116,18 @@ public class BlockRay { return (edge - c) / dir; } - private BlockFace computeCurrentFace(Axis axis, int sign) { + private AbsFace computeCurrentFace(Axis axis, int sign) { if (sign == 0) throw new IllegalStateException("sign is zero"); switch (axis) { case X: - return sign > 0 ? BlockFace.SOUTH : BlockFace.NORTH; + return sign > 0 ? AbsFace.NEG_X : AbsFace.POS_X; case Y: - return sign > 0 ? BlockFace.EAST : BlockFace.WEST; + return sign > 0 ? AbsFace.NEG_Y : AbsFace.POS_Y; default: case Z: - return sign > 0 ? BlockFace.BOTTOM : BlockFace.TOP; + return sign > 0 ? AbsFace.NEG_Z : AbsFace.POS_Z; } } @@ -137,7 +143,7 @@ public class BlockRay { return output; } - public BlockFace getCurrentFace() { + public AbsFace getCurrentFace() { return currentFace; } @@ -159,7 +165,8 @@ public class BlockRay { /** * Returns a smallest integer a such that a > c. * - * @param c the number to compute strict ceiling of + * @param c + * the number to compute strict ceiling of * @return the strict ceiling of c */ private static float strictCeil(float c) { @@ -169,7 +176,8 @@ public class BlockRay { /** * Returns a largest integer a such that a < c. * - * @param c the number to compute strict ceiling of + * @param c + * the number to compute strict ceiling of * @return the strict ceiling of c */ private static float strictFloor(float c) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 252429c..fe84518 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -1,560 +1,12 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package ru.windcorp.progressia.common.world; -import static ru.windcorp.progressia.common.world.block.BlockFace.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Objects; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.generic.ChunkGenericWO; import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileReference; -import ru.windcorp.progressia.common.world.tile.TileStackIsFullException; -public class ChunkData - implements GenericChunk { - - public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; - - private final Vec3i position = new Vec3i(); - private final WorldData world; - - private final BlockData[] blocks = new BlockData[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK]; - - private final TileDataStack[] tiles = new TileDataStack[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * - BLOCK_FACE_COUNT]; - - private Object generationHint = null; - - private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); - - public ChunkData(Vec3i position, WorldData world) { - this.position.set(position.x, position.y, position.z); - this.world = world; - } - - @Override - public Vec3i getPosition() { - return position; - } - - @Override - public BlockData getBlock(Vec3i posInChunk) { - return blocks[getBlockIndex(posInChunk)]; - } - - public void setBlock(Vec3i posInChunk, BlockData block, boolean notify) { - BlockData previous = blocks[getBlockIndex(posInChunk)]; - blocks[getBlockIndex(posInChunk)] = block; - - if (notify) { - getListeners().forEach(l -> { - l.onChunkBlockChanged(this, posInChunk, previous, block); - l.onChunkChanged(this); - }); - } - } - - @Override - public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { - return tiles[getTileIndex(blockInChunk, face)]; - } - - /** - * Internal use only. Modify a list returned by - * {@link #getTiles(Vec3i, BlockFace)} or - * {@link #getTilesOrNull(Vec3i, BlockFace)} - * to change tiles. - */ - protected void setTiles( - Vec3i blockInChunk, - BlockFace face, - TileDataStack tiles - ) { - this.tiles[getTileIndex(blockInChunk, face)] = tiles; - } - - @Override - public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { - return getTilesOrNull(blockInChunk, face) != null; - } - - @Override - public TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) { - int index = getTileIndex(blockInChunk, face); - - if (tiles[index] == null) { - createTileStack(blockInChunk, face); - } - - return tiles[index]; - } - - private void createTileStack(Vec3i blockInChunk, BlockFace face) { - Vec3i independentBlockInChunk = conjureIndependentBlockInChunkVec3i(blockInChunk); - TileDataStackImpl stack = new TileDataStackImpl(independentBlockInChunk, face); - setTiles(blockInChunk, face, stack); - } - - private Vec3i conjureIndependentBlockInChunkVec3i(Vec3i blockInChunk) { - for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { - TileDataStack stack = getTilesOrNull(blockInChunk, BlockFace.getFaces().get(i)); - if (stack instanceof TileDataStackImpl) { - return ((TileDataStackImpl) stack).blockInChunk; - } - } - - return new Vec3i(blockInChunk); - } - - private static int getBlockIndex(Vec3i posInChunk) { - checkLocalCoordinates(posInChunk); - - return posInChunk.z * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + - posInChunk.y * BLOCKS_PER_CHUNK + - posInChunk.x; - } - - private static int getTileIndex(Vec3i posInChunk, BlockFace face) { - return getBlockIndex(posInChunk) * BLOCK_FACE_COUNT + - face.getId(); - } - - private static void checkLocalCoordinates(Vec3i posInChunk) { - if (!isInBounds(posInChunk)) { - throw new IllegalCoordinatesException( - "Coordinates " + str(posInChunk) + " " - + "are not legal chunk coordinates" - ); - } - } - - public static boolean isInBounds(Vec3i posInChunk) { - return posInChunk.x >= 0 && posInChunk.x < BLOCKS_PER_CHUNK && - posInChunk.y >= 0 && posInChunk.y < BLOCKS_PER_CHUNK && - posInChunk.z >= 0 && posInChunk.z < BLOCKS_PER_CHUNK; - } - - public boolean isBorder(Vec3i blockInChunk, BlockFace face) { - final int min = 0, max = BLOCKS_PER_CHUNK - 1; - return (blockInChunk.x == min && face == SOUTH) || - (blockInChunk.x == max && face == NORTH) || - (blockInChunk.y == min && face == EAST) || - (blockInChunk.y == max && face == WEST) || - (blockInChunk.z == min && face == BOTTOM) || - (blockInChunk.z == max && face == TOP); - } - - public void forEachBlock(Consumer action) { - VectorUtil.iterateCuboid( - 0, - 0, - 0, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - action - ); - } - - public void forEachTileStack(Consumer action) { - forEachBlock(blockInChunk -> { - for (BlockFace face : BlockFace.getFaces()) { - TileDataStack stack = getTilesOrNull(blockInChunk, face); - if (stack == null) - continue; - action.accept(stack); - } - }); - } - - /** - * Iterates over all tiles in this chunk. - * - * @param action the action to perform. {@code TileLocation} refers to each - * tile using its primary block - */ - public void forEachTile(BiConsumer action) { - forEachTileStack(stack -> stack.forEach(tileData -> action.accept(stack, tileData))); - } - - public WorldData getWorld() { - return world; - } - - public Collection getListeners() { - return listeners; - } - - public void addListener(ChunkDataListener listener) { - this.listeners.add(listener); - } - - public void removeListener(ChunkDataListener listener) { - this.listeners.remove(listener); - } - - private static String str(Vec3i v) { - return "(" + v.x + "; " + v.y + "; " + v.z + ")"; - } - - protected void onLoaded() { - getListeners().forEach(l -> l.onChunkLoaded(this)); - } - - protected void beforeUnloaded() { - getListeners().forEach(l -> l.beforeChunkUnloaded(this)); - } - - public Object getGenerationHint() { - return generationHint; - } - - public void setGenerationHint(Object generationHint) { - this.generationHint = generationHint; - } - - /** - * Implementation of {@link TileDataStack} used internally by - * {@link ChunkData} to - * actually store the tiles. This is basically an array wrapper with - * reporting - * capabilities. - * - * @author javapony - */ - private class TileDataStackImpl extends TileDataStack { - private class TileReferenceImpl implements TileReference { - private int index; - - public TileReferenceImpl(int index) { - this.index = index; - } - - public void incrementIndex() { - this.index++; - } - - public void decrementIndex() { - this.index--; - } - - public void invalidate() { - this.index = 0; - } - - @Override - public TileData get() { - if (!isValid()) - return null; - return TileDataStackImpl.this.get(this.index); - } - - @Override - public int getIndex() { - return index; - } - - @Override - public TileDataStack getStack() { - return TileDataStackImpl.this; - } - - @Override - public boolean isValid() { - return this.index >= 0; - } - } - - private final TileData[] tiles = new TileData[TILES_PER_FACE]; - private int size = 0; - - private final TileReferenceImpl[] references = new TileReferenceImpl[tiles.length]; - private final int[] indicesByTag = new int[tiles.length]; - private final int[] tagsByIndex = new int[tiles.length]; - - { - Arrays.fill(indicesByTag, -1); - Arrays.fill(tagsByIndex, -1); - } - - /* - * Potentially shared - */ - private final Vec3i blockInChunk; - private final BlockFace face; - - public TileDataStackImpl(Vec3i blockInChunk, BlockFace face) { - this.blockInChunk = blockInChunk; - this.face = face; - } - - @Override - public Vec3i getBlockInChunk(Vec3i output) { - if (output == null) - output = new Vec3i(); - output.set(blockInChunk.x, blockInChunk.y, blockInChunk.z); - return output; - } - - @Override - public BlockFace getFace() { - return face; - } - - @Override - public ChunkData getChunk() { - return ChunkData.this; - } - - @Override - public int size() { - return size; - } - - @Override - public TileData get(int index) { - checkIndex(index, false); - - return tiles[index]; - } - - @Override - public TileData set(int index, TileData tile) { - Objects.requireNonNull(tile, "tile"); - TileData previous = get(index); // checks index - - tiles[index] = tile; - - if (references[index] != null) { - references[index].invalidate(); - references[index] = null; - } - - assert checkConsistency(); - - report(previous, tile); - return previous; - } - - @Override - public void add(int index, TileData tile) { - Objects.requireNonNull(tile, "tile"); - checkIndex(index, true); - - if (index != size()) { - System.arraycopy(tiles, index + 1, tiles, index + 2, size - index); - - for (int i = index; i < size; ++i) { - if (references[i] != null) { - references[i].incrementIndex(); - } - - indicesByTag[tagsByIndex[i]]++; - } - - System.arraycopy(references, index + 1, references, index + 2, size - index); - System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index + 2, size - index); - } - - size++; - tiles[index] = tile; - references[index] = null; - - for (int tag = 0; tag < indicesByTag.length; ++tag) { - if (tagsByIndex[tag] == -1) { - indicesByTag[tag] = index; - tagsByIndex[index] = tag; - break; - } - } - - modCount++; - assert checkConsistency(); - - report(null, tile); - } - - @Override - public void load(TileData tile, int tag) { - addFarthest(tile); - - int assignedTag = getIndexByTag(tag); - - if (assignedTag == tag) - return; - if (assignedTag == -1) { - throw new IllegalArgumentException( - "Tag " + tag + " already used by tile at index " + getIndexByTag(tag) - ); - } - - indicesByTag[tagsByIndex[size() - 1]] = -1; - tagsByIndex[size() - 1] = tag; - indicesByTag[tag] = size() - 1; - - assert checkConsistency(); - } - - @Override - public TileData remove(int index) { - TileData previous = get(index); // checks index - - if (references[index] != null) { - references[index].invalidate(); - } - - indicesByTag[tagsByIndex[index]] = -1; - - if (index != size() - 1) { - System.arraycopy(tiles, index + 1, tiles, index, size - index - 1); - - for (int i = index + 1; i < size; ++i) { - if (references[i] != null) { - references[i].decrementIndex(); - } - - indicesByTag[tagsByIndex[i]]--; - } - - System.arraycopy(references, index + 1, references, index, size - index - 1); - System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index, size - index - 1); - } - - size--; - tiles[size] = null; - references[size] = null; - tagsByIndex[size] = -1; - - modCount++; - assert checkConsistency(); - - report(previous, null); - return previous; - } - - @Override - public TileReference getReference(int index) { - checkIndex(index, false); - - if (references[index] == null) { - references[index] = new TileReferenceImpl(index); - } - - return references[index]; - } - - @Override - public int getIndexByTag(int tag) { - return indicesByTag[tag]; - } - - @Override - public int getTagByIndex(int index) { - checkIndex(index, false); - return tagsByIndex[index]; - } - - @Override - public void clear() { - while (!isEmpty()) { - removeFarthest(); - } - } - - private void checkIndex(int index, boolean isSizeAllowed) { - if (isSizeAllowed ? (index > size()) : (index >= size())) - throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: size is " + size); - - if (index < 0) - throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: index cannot be negative"); - - if (index >= TILES_PER_FACE) - throw new TileStackIsFullException( - "Index " + index + " is out of bounds: maximum tile stack size is " + TILES_PER_FACE - ); - } - - private void report(TileData previous, TileData current) { - ChunkData.this.getListeners().forEach(l -> { - if (previous != null) { - l.onChunkTilesChanged(ChunkData.this, blockInChunk, face, previous, false); - } - - if (current != null) { - l.onChunkTilesChanged(ChunkData.this, blockInChunk, face, current, true); - } - - l.onChunkChanged(ChunkData.this); - }); - } - - private boolean checkConsistency() { - int index; - - for (index = 0; index < size(); ++index) { - if (get(index) == null) - throw new AssertionError("get(index) is null"); - - if (references[index] != null) { - TileReference ref = getReference(index); - if (ref == null) - throw new AssertionError("references[index] is not null but getReference(index) is"); - if (!ref.isValid()) - throw new AssertionError("Reference is not valid"); - if (ref.get() != get(index)) - throw new AssertionError("Reference points to " + (ref.get() == null ? "null" : "wrong tile")); - if (ref.getIndex() != index) - throw new AssertionError("Reference has invalid index"); - if (ref.getStack() != this) - throw new AssertionError("Reference has invalid TDS"); - } - - if (index != indicesByTag[tagsByIndex[index]]) - throw new AssertionError("Tag mapping is inconsistent"); - if (index != getIndexByTag(getTagByIndex(index))) - throw new AssertionError("Tag methods are inconsistent with tag mapping"); - } - - for (; index < tiles.length; ++index) { - if (tiles[index] != null) - throw new AssertionError("Leftover tile detected"); - if (references[index] != null) - throw new AssertionError("Leftover reference detected"); - if (tagsByIndex[index] != -1) - throw new AssertionError("Leftover tags detected"); - } - - return true; - } - - } +public interface ChunkData + extends ChunkDataRO, ChunkGenericWO { + + // currently empty } diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java index 72008c4..22b4fb3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.common.world; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface ChunkDataListener { @@ -36,7 +36,7 @@ public interface ChunkDataListener { * @param previous the previous occupant of {@code blockInChunk} * @param current the current (new) occupant of {@code blockInChunk} */ - default void onChunkBlockChanged(ChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current) { + default void onChunkBlockChanged(DefaultChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current) { } /** @@ -53,9 +53,9 @@ public interface ChunkDataListener { * {@code false} iff the tile has been removed */ default void onChunkTilesChanged( - ChunkData chunk, + DefaultChunkData chunk, Vec3i blockInChunk, - BlockFace face, + RelFace face, TileData tile, boolean wasAdded ) { @@ -70,7 +70,7 @@ public interface ChunkDataListener { * * @param chunk the chunk that has changed */ - default void onChunkChanged(ChunkData chunk) { + default void onChunkChanged(DefaultChunkData chunk) { } /** @@ -78,7 +78,7 @@ public interface ChunkDataListener { * * @param chunk the chunk that has loaded */ - default void onChunkLoaded(ChunkData chunk) { + default void onChunkLoaded(DefaultChunkData chunk) { } /** @@ -86,7 +86,7 @@ public interface ChunkDataListener { * * @param chunk the chunk that is going to be loaded */ - default void beforeChunkUnloaded(ChunkData chunk) { + default void beforeChunkUnloaded(DefaultChunkData chunk) { } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java index b39437c..63a164a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; import java.util.function.Consumer; @@ -28,7 +28,7 @@ public class ChunkDataListeners { public static WorldDataListener createAdder(Supplier listenerSupplier) { return new WorldDataListener() { @Override - public void getChunkListeners(WorldData world, Vec3i chunk, Consumer chunkListenerSink) { + public void getChunkListeners(DefaultWorldData world, Vec3i chunk, Consumer chunkListenerSink) { chunkListenerSink.accept(listenerSupplier.get()); } }; diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataRO.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataRO.java new file mode 100644 index 0000000..08ce159 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataRO.java @@ -0,0 +1,12 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface ChunkDataRO + extends ChunkGenericRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java b/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java index 55f2076..a8a454e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java +++ b/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java @@ -15,10 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; -import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; +import static ru.windcorp.progressia.common.world.DefaultChunkData.BLOCKS_PER_CHUNK; import glm.vec._3.i.Vec3i; @@ -29,20 +29,17 @@ import glm.vec._3.i.Vec3i; * Three types of coordinates are used in Progressia: *

      *
    • World coordinates, in code referred to as - * {@code blockInWorld} - - * coordinates relative to world origin. Every block in the world has unique - * world coordinates.
    • + * {@code blockInWorld} - coordinates relative to world origin. Every block in + * the world has unique world coordinates. *
    • Chunk coordinates, in code referred to as - * {@code blockInChunk} - - * coordinates relative some chunk's origin. Every block in the chunk has unique - * chunk coordinates, but blocks in different chunks may have identical chunk - * coordinates. These coordinates are only useful in combination with a chunk - * reference. Chunk coordinates are always + * {@code blockInChunk} - coordinates relative some chunk's origin. Every block + * in the chunk has unique chunk coordinates, but blocks in different chunks may + * have identical chunk coordinates. These coordinates are only useful in + * combination with a chunk reference. Chunk coordinates are always * [0; {@link #BLOCKS_PER_CHUNK}).
    • *
    • Coordinates of chunk, in code referred to as - * {@code chunk} - - * chunk coordinates relative to world origin. Every chunk in the world has - * unique coordinates of chunk.
    • + * {@code chunk} - chunk coordinates relative to world origin. Every chunk in + * the world has unique coordinates of chunk. *
    */ public class Coordinates { @@ -55,7 +52,8 @@ public class Coordinates { * Computes the coordinate of the chunk that the block specified by the * provided world coordinate belongs to. * - * @param blockInWorld world coordinate of the block + * @param blockInWorld + * world coordinate of the block * @return the corresponding coordinate of the chunk containing the block * @see #convertInWorldToChunk(Vec3i, Vec3i) */ @@ -67,15 +65,14 @@ public class Coordinates { * Computes the coordinates of the chunk that the block specified by the * provided world coordinates belongs to. * - * @param blockInWorld world coordinates of the block - * @param output a {@link Vec3i} to store the result in + * @param blockInWorld + * world coordinates of the block + * @param output + * a {@link Vec3i} to store the result in * @return {@code output} * @see #convertInWorldToChunk(int) */ - public static Vec3i convertInWorldToChunk( - Vec3i blockInWorld, - Vec3i output - ) { + public static Vec3i convertInWorldToChunk(Vec3i blockInWorld, Vec3i output) { if (output == null) output = new Vec3i(); @@ -87,10 +84,11 @@ public class Coordinates { } /** - * Computes the chunk coordinate that the block specified by the - * provided world coordinate has in its chunk. + * Computes the chunk coordinate that the block specified by the provided + * world coordinate has in its chunk. * - * @param blockInWorld world coordinate of the block + * @param blockInWorld + * world coordinate of the block * @return the corresponding chunk coordinate of the block * @see #convertInWorldToInChunk(Vec3i, Vec3i) */ @@ -99,18 +97,17 @@ public class Coordinates { } /** - * Computes the chunk coordinates that the block specified by the - * provided world coordinates has in its chunk. + * Computes the chunk coordinates that the block specified by the provided + * world coordinates has in its chunk. * - * @param blockInWorld world coordinates of the block - * @param output a {@link Vec3i} to store the result in + * @param blockInWorld + * world coordinates of the block + * @param output + * a {@link Vec3i} to store the result in * @return {@code output} * @see #convertInWorldToInChunk(int) */ - public static Vec3i convertInWorldToInChunk( - Vec3i blockInWorld, - Vec3i output - ) { + public static Vec3i convertInWorldToInChunk(Vec3i blockInWorld, Vec3i output) { if (output == null) output = new Vec3i(); @@ -125,8 +122,10 @@ public class Coordinates { * Computes the world coordinate of the block specified by its chunk * coordinate and the coordinate of its chunk. * - * @param chunk coordinate of chunk - * @param blockInChunk chunk coordinate of block + * @param chunk + * coordinate of chunk + * @param blockInChunk + * chunk coordinate of block * @return corresponding world coordinate * @see #getInWorld(int, int) */ @@ -138,17 +137,16 @@ public class Coordinates { * Computes the world coordinates of the block specified by its chunk * coordinates and the coordinates of its chunk. * - * @param chunk coordinate of chunk - * @param blockInChunk chunk coordinate of block - * @param output a {@link Vec3i} to store the result in + * @param chunk + * coordinate of chunk + * @param blockInChunk + * chunk coordinate of block + * @param output + * a {@link Vec3i} to store the result in * @return {@code output} * @see #getInWorld(int) */ - public static Vec3i getInWorld( - Vec3i chunk, - Vec3i blockInChunk, - Vec3i output - ) { + public static Vec3i getInWorld(Vec3i chunk, Vec3i blockInChunk, Vec3i output) { if (output == null) output = new Vec3i(); @@ -158,7 +156,7 @@ public class Coordinates { return output; } - + public static boolean isOnChunkBorder(int blockInChunk) { return blockInChunk == 0 || blockInChunk == BLOCKS_PER_CHUNK - 1; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/DecodingException.java b/src/main/java/ru/windcorp/progressia/common/world/DecodingException.java index 532d22f..410bfad 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/DecodingException.java +++ b/src/main/java/ru/windcorp/progressia/common/world/DecodingException.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; /** diff --git a/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java new file mode 100644 index 0000000..e11509b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java @@ -0,0 +1,529 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world; + +import static ru.windcorp.progressia.common.world.rels.BlockFace.BLOCK_FACE_COUNT; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; + +import glm.vec._3.i.Vec3i; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.common.world.tile.TileStackIsFullException; + +/** + * The implementation of {@link ChunkData} used to store the actual game world. + * This class should be considered an implementation detail. + */ +public class DefaultChunkData implements ChunkData { + + public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; + public static final int CHUNK_RADIUS = BLOCKS_PER_CHUNK / 2; + + private final Vec3i position = new Vec3i(); + private final DefaultWorldData world; + + private final BlockData[] blocks = new BlockData[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK]; + + private final TileDataStack[] tiles = new TileDataStack[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + * BLOCK_FACE_COUNT]; + + private final AbsFace up; + + private Object generationHint = null; + + private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); + + public DefaultChunkData(Vec3i position, DefaultWorldData world) { + this.position.set(position.x, position.y, position.z); + this.world = world; + this.up = world.getGravityModel().getDiscreteUp(position); + } + + @Override + public Vec3i getPosition() { + return position; + } + + @Override + public AbsFace getUp() { + return up; + } + + @Override + public BlockData getBlock(Vec3i posInChunk) { + return blocks[getBlockIndex(posInChunk)]; + } + + @Override + public void setBlock(Vec3i posInChunk, BlockData block, boolean notify) { + BlockData previous = blocks[getBlockIndex(posInChunk)]; + blocks[getBlockIndex(posInChunk)] = block; + + if (notify) { + getListeners().forEach(l -> { + l.onChunkBlockChanged(this, posInChunk, previous, block); + l.onChunkChanged(this); + }); + } + } + + @Override + public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { + return tiles[getTileIndex(blockInChunk, face)]; + } + + /** + * Internal use only. Modify a list returned by + * {@link #getTiles(Vec3i, BlockFace)} or + * {@link #getTilesOrNull(Vec3i, BlockFace)} + * to change tiles. + */ + protected void setTiles( + Vec3i blockInChunk, + BlockFace face, + TileDataStack tiles + ) { + this.tiles[getTileIndex(blockInChunk, face)] = tiles; + } + + @Override + public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { + return getTilesOrNull(blockInChunk, face) != null; + } + + @Override + public TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) { + int index = getTileIndex(blockInChunk, face); + + if (tiles[index] == null) { + createTileStack(blockInChunk, face); + } + + return tiles[index]; + } + + private void createTileStack(Vec3i blockInChunk, BlockFace face) { + Vec3i independentBlockInChunk = conjureIndependentBlockInChunkVec3i(blockInChunk); + TileDataStackImpl stack = new TileDataStackImpl(independentBlockInChunk, face); + setTiles(blockInChunk, face, stack); + } + + private Vec3i conjureIndependentBlockInChunkVec3i(Vec3i blockInChunk) { + for (int i = 0; i < AbsFace.BLOCK_FACE_COUNT; ++i) { + TileDataStack stack = getTilesOrNull(blockInChunk, AbsFace.getFaces().get(i)); + if (stack instanceof TileDataStackImpl) { + return ((TileDataStackImpl) stack).blockInChunk; + } + } + + return new Vec3i(blockInChunk); + } + + private static int getBlockIndex(Vec3i posInChunk) { + checkLocalCoordinates(posInChunk); + + return posInChunk.z * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + + posInChunk.y * BLOCKS_PER_CHUNK + + posInChunk.x; + } + + private int getTileIndex(Vec3i posInChunk, BlockFace face) { + return getBlockIndex(posInChunk) * BLOCK_FACE_COUNT + + face.resolve(getUp()).getId(); + } + + private static void checkLocalCoordinates(Vec3i posInChunk) { + if (!GenericChunks.containsBiC(posInChunk)) { + throw new IllegalCoordinatesException( + "Coordinates (" + posInChunk.x + "; " + posInChunk.y + "; " + posInChunk.z + ") " + + "are not legal chunk coordinates" + ); + } + } + + public DefaultWorldData getWorld() { + return world; + } + + public Collection getListeners() { + return listeners; + } + + public void addListener(ChunkDataListener listener) { + this.listeners.add(listener); + } + + public void removeListener(ChunkDataListener listener) { + this.listeners.remove(listener); + } + + protected void onLoaded() { + getListeners().forEach(l -> l.onChunkLoaded(this)); + } + + protected void beforeUnloaded() { + getListeners().forEach(l -> l.beforeChunkUnloaded(this)); + } + + public Object getGenerationHint() { + return generationHint; + } + + public void setGenerationHint(Object generationHint) { + this.generationHint = generationHint; + } + + /** + * Implementation of {@link TileDataStack} used internally by + * {@link DefaultChunkData} to + * actually store the tiles. This is basically an array wrapper with + * reporting + * capabilities. + * + * @author javapony + */ + private class TileDataStackImpl extends AbstractList implements TileDataStack { + private class TileDataReferenceImpl implements TileDataReference { + private int index; + + public TileDataReferenceImpl(int index) { + this.index = index; + } + + public void incrementIndex() { + this.index++; + } + + public void decrementIndex() { + this.index--; + } + + public void invalidate() { + this.index = -1; + } + + @Override + public TileData get() { + if (!isValid()) + return null; + return TileDataStackImpl.this.get(this.index); + } + + @Override + public int getIndex() { + return index; + } + + @Override + public TileDataStack getStack() { + return TileDataStackImpl.this; + } + + @Override + public boolean isValid() { + return this.index >= 0; + } + } + + private final TileData[] tiles = new TileData[TILES_PER_FACE]; + private int size = 0; + + private final TileDataReferenceImpl[] references = new TileDataReferenceImpl[tiles.length]; + private final int[] indicesByTag = new int[tiles.length]; + private final int[] tagsByIndex = new int[tiles.length]; + + { + Arrays.fill(indicesByTag, -1); + Arrays.fill(tagsByIndex, -1); + } + + /* + * Potentially shared + */ + private final Vec3i blockInChunk; + private final RelFace face; + + public TileDataStackImpl(Vec3i blockInChunk, BlockFace face) { + this.blockInChunk = blockInChunk; + this.face = face.relativize(getUp()); + } + + @Override + public Vec3i getBlockInChunk(Vec3i output) { + if (output == null) + output = new Vec3i(); + output.set(blockInChunk.x, blockInChunk.y, blockInChunk.z); + return output; + } + + @Override + public RelFace getFace() { + return face; + } + + @Override + public DefaultChunkData getChunk() { + return DefaultChunkData.this; + } + + @Override + public int size() { + return size; + } + + @Override + public TileData get(int index) { + checkIndex(index, false); + + return tiles[index]; + } + + @Override + public TileData set(int index, TileData tile) { + Objects.requireNonNull(tile, "tile"); + TileData previous = get(index); // checks index + + tiles[index] = tile; + + if (references[index] != null) { + references[index].invalidate(); + references[index] = null; + } + + assert checkConsistency(); + + report(previous, tile); + return previous; + } + + @Override + public void add(int index, TileData tile) { + Objects.requireNonNull(tile, "tile"); + checkIndex(index, true); + + if (index != size()) { + System.arraycopy(tiles, index + 1, tiles, index + 2, size - index); + + for (int i = index; i < size; ++i) { + if (references[i] != null) { + references[i].incrementIndex(); + } + + indicesByTag[tagsByIndex[i]]++; + } + + System.arraycopy(references, index + 1, references, index + 2, size - index); + System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index + 2, size - index); + } + + size++; + tiles[index] = tile; + references[index] = null; + + for (int tag = 0; tag < indicesByTag.length; ++tag) { + if (indicesByTag[tag] == -1) { + indicesByTag[tag] = index; + tagsByIndex[index] = tag; + break; + } + } + + modCount++; + assert checkConsistency(); + + report(null, tile); + } + + @Override + public void load(TileData tile, int tag) { + addFarthest(tile); + + int assignedIndex = size() - 1; + + // Skip if we already have the correct tag + int assignedTag = getTagByIndex(assignedIndex); + if (assignedTag == tag) { + return; + } + assert assignedTag != -1 : "Adding farthest tile resulted in -1 tag"; + + // Make sure we aren't trying to assign a tag already in use + int tileWithRequestedTag = getIndexByTag(tag); + if (tileWithRequestedTag != -1) { + throw new IllegalArgumentException( + "Tag " + tag + " already used by tile at index " + tileWithRequestedTag + ); + } + assert tileWithRequestedTag != assignedIndex + : "tag == assignedTag yet tileWithRequestedTag != assignedIndex"; + + // Do the tag editing + indicesByTag[assignedTag] = -1; // Release assigned tag + tagsByIndex[assignedIndex] = tag; // Reroute assigned index to + // requested tag + indicesByTag[tag] = assignedIndex; // Claim requested tag + assert checkConsistency(); + } + + @Override + public TileData remove(int index) { + TileData previous = get(index); // checks index + + if (references[index] != null) { + references[index].invalidate(); + } + + indicesByTag[tagsByIndex[index]] = -1; + + if (index != size() - 1) { + System.arraycopy(tiles, index + 1, tiles, index, size - index - 1); + + for (int i = index + 1; i < size; ++i) { + if (references[i] != null) { + references[i].decrementIndex(); + } + + indicesByTag[tagsByIndex[i]]--; + } + + System.arraycopy(references, index + 1, references, index, size - index - 1); + System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index, size - index - 1); + } + + size--; + tiles[size] = null; + references[size] = null; + tagsByIndex[size] = -1; + + modCount++; + assert checkConsistency(); + + report(previous, null); + return previous; + } + + @Override + public TileDataReference getReference(int index) { + checkIndex(index, false); + + if (references[index] == null) { + references[index] = new TileDataReferenceImpl(index); + } + + return references[index]; + } + + @Override + public int getIndexByTag(int tag) { + return indicesByTag[tag]; + } + + @Override + public int getTagByIndex(int index) { + checkIndex(index, false); + return tagsByIndex[index]; + } + + @Override + public void clear() { + while (!isEmpty()) { + removeFarthest(); + } + } + + private void checkIndex(int index, boolean isSizeAllowed) { + if (isSizeAllowed ? (index > size()) : (index >= size())) + throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: size is " + size); + + if (index < 0) + throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: index cannot be negative"); + + if (index >= TILES_PER_FACE) + throw new TileStackIsFullException( + "Index " + index + " is out of bounds: maximum tile stack size is " + TILES_PER_FACE + ); + } + + private void report(TileData previous, TileData current) { + DefaultChunkData.this.getListeners().forEach(l -> { + if (previous != null) { + l.onChunkTilesChanged(DefaultChunkData.this, blockInChunk, face, previous, false); + } + + if (current != null) { + l.onChunkTilesChanged(DefaultChunkData.this, blockInChunk, face, current, true); + } + + l.onChunkChanged(DefaultChunkData.this); + }); + } + + private boolean checkConsistency() { + int index; + + for (index = 0; index < size(); ++index) { + if (get(index) == null) + throw new AssertionError("get(index) is null"); + + if (references[index] != null) { + TileDataReference ref = getReference(index); + if (ref == null) + throw new AssertionError("references[index] is not null but getReference(index) is"); + if (!ref.isValid()) + throw new AssertionError("Reference is not valid"); + if (ref.get() != get(index)) + throw new AssertionError("Reference points to " + (ref.get() == null ? "null" : "wrong tile")); + if (ref.getIndex() != index) + throw new AssertionError("Reference has invalid index"); + if (ref.getStack() != this) + throw new AssertionError("Reference has invalid TDS"); + } + + if (index != indicesByTag[tagsByIndex[index]]) + throw new AssertionError("Tag mapping is inconsistent"); + if (index != getIndexByTag(getTagByIndex(index))) + throw new AssertionError("Tag methods are inconsistent with tag mapping"); + } + + for (; index < tiles.length; ++index) { + if (tiles[index] != null) + throw new AssertionError("Leftover tile detected"); + if (references[index] != null) + throw new AssertionError("Leftover reference detected"); + if (tagsByIndex[index] != -1) + throw new AssertionError("Leftover tags detected"); + } + + return true; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/DefaultWorldData.java b/src/main/java/ru/windcorp/progressia/common/world/DefaultWorldData.java new file mode 100644 index 0000000..1de79a6 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/DefaultWorldData.java @@ -0,0 +1,262 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import gnu.trove.TCollections; +import gnu.trove.map.TLongObjectMap; +import gnu.trove.map.hash.TLongObjectHashMap; +import gnu.trove.set.TLongSet; +import ru.windcorp.progressia.common.collision.CollisionModel; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.ChunkMap; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.generic.LongBasedChunkMap; + +public class DefaultWorldData implements WorldData { + + private final ChunkMap chunksByPos = new LongBasedChunkMap<>( + TCollections.synchronizedMap(new TLongObjectHashMap<>()) + ); + + private final Collection chunks = Collections.unmodifiableCollection(chunksByPos.values()); + + private final TLongObjectMap entitiesById = TCollections.synchronizedMap(new TLongObjectHashMap<>()); + + private final Collection entities = Collections.unmodifiableCollection(entitiesById.valueCollection()); + + private GravityModel gravityModel = null; + + private float time = 0; + + private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); + + public DefaultWorldData() { + + } + + @Override + public DefaultChunkData getChunk(Vec3i pos) { + return chunksByPos.get(pos); + } + + @Override + public DefaultChunkData getChunkByBlock(Vec3i blockInWorld) { + return (DefaultChunkData) WorldData.super.getChunkByBlock(blockInWorld); + } + + @Override + public Collection getChunks() { + return chunks; + } + + public ChunkSet getLoadedChunks() { + return chunksByPos.keys(); + } + + @Override + public Collection getEntities() { + return entities; + } + + @Override + public void forEachEntity(Consumer action) { + synchronized (entitiesById) { // TODO HORRIBLY MUTILATE THE CORPSE OF + // TROVE4J so that + // gnu.trove.impl.sync.SynchronizedCollection.forEach + // is synchronized + getEntities().forEach(action); + } + } + + public TLongSet getLoadedEntities() { + return entitiesById.keySet(); + } + + private void addChunkListeners(DefaultChunkData chunk) { + getListeners().forEach(l -> l.getChunkListeners(this, chunk.getPosition(), chunk::addListener)); + } + + public synchronized void addChunk(DefaultChunkData chunk) { + addChunkListeners(chunk); + + DefaultChunkData previous = chunksByPos.get(chunk); + if (previous != null) { + throw new IllegalArgumentException( + String.format( + "Chunk at (%d; %d; %d) already exists", + chunk.getPosition().x, + chunk.getPosition().y, + chunk.getPosition().z + ) + ); + } + + chunksByPos.put(chunk, chunk); + + chunk.onLoaded(); + getListeners().forEach(l -> l.onChunkLoaded(this, chunk)); + } + + public synchronized void removeChunk(DefaultChunkData chunk) { + getListeners().forEach(l -> l.beforeChunkUnloaded(this, chunk)); + chunk.beforeUnloaded(); + + chunksByPos.remove(chunk); + } + + @Override + public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { + DefaultChunkData chunk = getChunkByBlock(blockInWorld); + if (chunk == null) + throw new IllegalCoordinatesException( + "Coordinates " + + "(" + blockInWorld.x + "; " + blockInWorld.y + "; " + blockInWorld.z + ") " + + "do not belong to a loaded chunk" + ); + + chunk.setBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null), block, notify); + } + + @Override + public TileDataStack getTiles(Vec3i blockInWorld, BlockFace face) { + return WorldData.super.getTiles(blockInWorld, face); + } + + @Override + public EntityData getEntity(long entityId) { + return entitiesById.get(entityId); + } + + @Override + public void addEntity(EntityData entity) { + Objects.requireNonNull(entity, "entity"); + + EntityData previous = entitiesById.putIfAbsent(entity.getEntityId(), entity); + + if (previous != null) { + String message = "Cannot add entity " + entity + ": "; + + if (previous == entity) { + message += "already present"; + } else { + message += "entity with the same EntityID already present (" + previous + ")"; + } + + throw new IllegalStateException(message); + } + + getListeners().forEach(l -> l.onEntityAdded(this, entity)); + } + + @Override + public void removeEntity(long entityId) { + synchronized (entitiesById) { + EntityData entity = entitiesById.get(entityId); + + if (entity == null) { + throw new IllegalArgumentException( + "Entity with EntityID " + EntityData.formatEntityId(entityId) + " not present" + ); + } else { + removeEntity(entity); + } + } + } + + @Override + public void removeEntity(EntityData entity) { + Objects.requireNonNull(entity, "entity"); + + getListeners().forEach(l -> l.beforeEntityRemoved(this, entity)); + entitiesById.remove(entity.getEntityId()); + } + + @Override + public void changeEntity(SE entity, StateChange change) { + change.change(entity); + } + + @Override + public float getTime() { + return time; + } + + @Override + public void advanceTime(float change) { + this.time += change; + } + + public CollisionModel getCollisionModelOfBlock(Vec3i blockInWorld) { + DefaultChunkData chunk = getChunkByBlock(blockInWorld); + if (chunk == null) + return null; + + BlockData block = chunk.getBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null)); + if (block == null) + return null; + return block.getCollisionModel(); + } + + /** + * @return the gravity model + */ + @Override + public GravityModel getGravityModel() { + return gravityModel; + } + + /** + * @param gravityModel the gravity model to set + */ + public void setGravityModel(GravityModel gravityModel) { + if (!chunks.isEmpty()) { + throw new IllegalStateException( + "Attempted to change gravity model to " + gravityModel + " while " + chunks.size() + + " chunks were loaded" + ); + } + + this.gravityModel = gravityModel; + } + + public Collection getListeners() { + return listeners; + } + + public void addListener(WorldDataListener e) { + listeners.add(e); + } + + public void removeListener(WorldDataListener o) { + listeners.remove(o); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java b/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java new file mode 100644 index 0000000..917d45f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java @@ -0,0 +1,230 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Objects; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.crash.CrashReports; +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.rels.AbsFace; + +/** + * Gravity model specifies the gravitational acceleration field, the up + * direction field and the discrete up direction field. + *

    + * A gravity model may be queried for the vector of gravitational acceleration + * that should affect an object. This vector is, generally speaking, a function + * of space: gravity in two different locations may vary. Gravity may also be a + * zero vector. + *

    + * The vector of gravitational acceleration defines the up direction. Up vector + * is defined as the additive inverse of the normalized gravitational + * acceleration vector or {@code (0; 0; 0)} if there is no gravity. + *

    + * Separately from the gravitational acceleration and the up vectors, a + * discrete up vector field is specified by a gravity model. This field + * is defined for each chunk uniquely and may only take the value of one of the + * six {@linkplain AbsFace absolute directions}. This vector specifies the + * rotation of blocks, tiles and other objects that may not have a + * non-axis-aligned direction. Discrete up vector must be specified even for + * chunks that have a zero or an ambiguous up direction. Although discrete up + * direction is not technically linked to the up direction, is it expected by + * the players that they generally align. + * + * @author javapony + */ +public abstract class GravityModel extends Namespaced { + + public GravityModel(String id) { + super(id); + } + + /** + * Computes the vector of gravitational acceleration at the provided + * location. + * + * @param pos the position to compute gravity at + * @param output a {@link Vec3} where the result is stored. May be + * {@code null}. + * @return the vector of gravitational acceleration. The returned object + * will match {@code output} parameter is it is non-null. + */ + public Vec3 getGravity(Vec3 pos, Vec3 output) { + Objects.requireNonNull(pos, "pos"); + + if (output == null) { + output = new Vec3(); + } + + try { + doGetGravity(pos, output); + } catch (Exception e) { + throw CrashReports.report(e, "%s failed to compute gravity at (%d; %d; %d)", this, pos.x, pos.y, pos.z); + } + + return output; + } + + /** + * Computes the up direction at the provided location. Up vector is defined + * as the additive inverse of the normalized gravitational acceleration + * vector or {@code (0; 0; 0)} if there is no gravity. + * + * @param pos the position to compute up vector at + * @param output a {@link Vec3} where the result is stored. May be + * {@code null}. + * @return the up vector. The returned object will match {@code output} + * parameter is it is non-null. + */ + public Vec3 getUp(Vec3 pos, Vec3 output) { + output = getGravity(pos, output); + + if (output.any()) { + output.normalize().negate(); + } + + return output; + } + + /** + * Computes the discrete up vector for the chunk at the specified + * coordinates. + * + * @param chunkPos the coordinates of chunk to compute discrete up at + * @return an {@link AbsFace} that corresponds to the up direction in the + * specified chunk. Never {@code null}. + */ + public AbsFace getDiscreteUp(Vec3i chunkPos) { + Objects.requireNonNull(chunkPos, "chunkPos"); + + final AbsFace result; + + try { + result = doGetDiscreteUp(chunkPos); + } catch (Exception e) { + throw CrashReports.report( + e, + "%s failed to compute discrete up at (%d; %d; %d)", + this, + chunkPos.x, + chunkPos.y, + chunkPos.z + ); + } + + if (result == null) { + throw CrashReports.report( + null, + "%s has computed null as the discrete up at (%d; %d; %d). This is forbidden.", + this, + chunkPos.x, + chunkPos.y, + chunkPos.z + ); + } + + return result; + } + + /** + * Computes the gravitational acceleration vector at the provided location. + * Actual computation of gravity is delegated to this method by the other + * methods in this class. + * + * @param pos the position to compute gravity at + * @param output a {@link Vec3} where the result must be stored. Never + * {@code null}. + */ + protected abstract void doGetGravity(Vec3 pos, Vec3 output); + + /** + * Computes the discrete up vector for the chunk at the specified + * coordinates. A direction must be assigned under any circumstances. Actual + * computation of discrete up is delegated to this method by the other + * methods in this class. + * + * @param chunkPos the coordinates of chunk to compute discrete up at + * @return an {@link AbsFace} that corresponds to the up direction in the + * specified chunk. Never {@code null}. + */ + protected abstract AbsFace doGetDiscreteUp(Vec3i chunkPos); + + /** + * Parses the settings from the provided {@link DataInput} and configures this object appropriately. This method will not necessarily exhaust the input. + * @param input a stream to read the settings from + * @throws IOException if an I/O error occurs + * @throws DecodingException if the settings could not be parsed from input + */ + public void readSettings(DataInput input) throws IOException, DecodingException { + Objects.requireNonNull(input, "input"); + + try { + doReadSettings(input); + } catch (IOException | DecodingException e) { + throw e; + } catch (Exception e) { + throw CrashReports.report( + e, + "%s failed to read its settings", + this + ); + } + } + + /** + * Encodes the settings of this model into the provided {@link DataOutput}. + * @param output a stream to write the settings into + * @throws IOException if an I/O error occurs + */ + public void writeSettings(DataOutput output) throws IOException { + Objects.requireNonNull(output, "output"); + + try { + doWriteSettings(output); + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw CrashReports.report( + e, + "%s failed to write its settings", + this + ); + } + } + + /** + * Parses the settings from the provided {@link DataInput} and configures this object appropriately. This method will not necessarily exhaust the input. + * @param input a stream to read the settings from + * @throws IOException if an I/O error occurs + * @throws DecodingException if the settings could not be parsed from input + */ + protected abstract void doReadSettings(DataInput input) throws IOException, DecodingException; + + /** + * Encodes the settings of this model into the provided {@link DataOutput}. + * @param output a stream to write the settings into + * @throws IOException if an I/O error occurs + */ + protected abstract void doWriteSettings(DataOutput output) throws IOException; + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java new file mode 100644 index 0000000..776e04f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java @@ -0,0 +1,30 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.util.namespaces.NamespacedFactoryRegistry; + +public class GravityModelRegistry extends NamespacedFactoryRegistry { + + public static final GravityModelRegistry INSTANCE = new GravityModelRegistry(); + + public static GravityModelRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/IllegalCoordinatesException.java b/src/main/java/ru/windcorp/progressia/common/world/IllegalCoordinatesException.java index 69240cf..1c3a3d3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/IllegalCoordinatesException.java +++ b/src/main/java/ru/windcorp/progressia/common/world/IllegalCoordinatesException.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; public class IllegalCoordinatesException extends RuntimeException { @@ -38,12 +38,8 @@ public class IllegalCoordinatesException extends RuntimeException { super(message, cause); } - public IllegalCoordinatesException( - String message, - Throwable cause, - boolean enableSuppression, - boolean writableStackTrace - ) { + public IllegalCoordinatesException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketAffectChunk.java b/src/main/java/ru/windcorp/progressia/common/world/PacketAffectChunk.java index 95e6eab..fdd4ce3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketAffectChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketAffectChunk.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; import glm.vec._3.i.Vec3i; diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java b/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java index 8433b9b..64f3257 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; import ru.windcorp.progressia.common.comms.packets.Packet; @@ -26,6 +26,6 @@ public abstract class PacketAffectWorld extends Packet { super(id); } - public abstract void apply(WorldData world); + public abstract void apply(DefaultWorldData world); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java b/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java index c65b045..01e8df9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; import java.io.DataInput; @@ -53,9 +53,9 @@ public class PacketRevokeChunk extends PacketAffectChunk { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { synchronized (world) { - ChunkData chunk = world.getChunk(position); + DefaultChunkData chunk = world.getChunk(position); if (chunk != null) { world.removeChunk(chunk); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java b/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java index ca079ff..2615b94 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; import java.io.DataInput; @@ -41,7 +41,7 @@ public class PacketSendChunk extends PacketAffectChunk { super(id); } - public void set(ChunkData chunk) { + public void set(DefaultChunkData chunk) { this.position.set(chunk.getX(), chunk.getY(), chunk.getZ()); try { @@ -67,7 +67,7 @@ public class PacketSendChunk extends PacketAffectChunk { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { try { world.addChunk(ChunkIO.load(world, position, data.getReader(), IOContext.COMMS)); } catch (DecodingException | IOException e) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java b/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java new file mode 100644 index 0000000..454a1fa --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java @@ -0,0 +1,76 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import ru.windcorp.progressia.common.util.DataBuffer; +import ru.windcorp.progressia.common.util.crash.CrashReports; + +public class PacketSetGravityModel extends PacketAffectWorld { + + private String gravityModelId; + private final DataBuffer settings = new DataBuffer(); + + public PacketSetGravityModel() { + this("Core:SetGravityModel"); + } + + protected PacketSetGravityModel(String id) { + super(id); + } + + public void set(GravityModel model) { + this.gravityModelId = model.getId(); + + try { + model.writeSettings(settings.getWriter()); + } catch (IOException e) { + throw CrashReports.report(e, "%s has errored when writing its settings", model); + } + } + + @Override + public void read(DataInput input) throws IOException, DecodingException { + gravityModelId = input.readUTF(); + settings.fill(input, input.readInt()); + } + + @Override + public void write(DataOutput output) throws IOException { + output.writeUTF(gravityModelId); + output.writeInt(settings.getSize()); + settings.flush(output); + } + + @Override + public void apply(DefaultWorldData world) { + GravityModel model = GravityModelRegistry.getInstance().create(gravityModelId); + world.setGravityModel(model); + try { + model.readSettings(settings.getReader()); + } catch (IOException e) { + throw CrashReports.report(e, "%s has errored when reading its settings", model); + } catch (DecodingException e) { + throw CrashReports.report(e, "%s has failed to parse its settings", model); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketSetLocalPlayer.java b/src/main/java/ru/windcorp/progressia/common/world/PacketSetLocalPlayer.java index f835614..625a4c5 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketSetLocalPlayer.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketSetLocalPlayer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; import java.io.DataInput; diff --git a/src/main/java/ru/windcorp/progressia/common/world/PlayerData.java b/src/main/java/ru/windcorp/progressia/common/world/PlayerData.java index 2123e3f..ecd512b 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PlayerData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PlayerData.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; import ru.windcorp.progressia.common.world.entity.EntityData; diff --git a/src/main/java/ru/windcorp/progressia/common/world/TileDataReference.java b/src/main/java/ru/windcorp/progressia/common/world/TileDataReference.java new file mode 100644 index 0000000..ccc118b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/TileDataReference.java @@ -0,0 +1,10 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceWO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataReference extends TileDataReferenceRO, + TileGenericReferenceWO { + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/TileDataReferenceRO.java b/src/main/java/ru/windcorp/progressia/common/world/TileDataReferenceRO.java new file mode 100644 index 0000000..59257ec --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/TileDataReferenceRO.java @@ -0,0 +1,12 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataReferenceRO + extends TileGenericReferenceRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/TileDataStack.java b/src/main/java/ru/windcorp/progressia/common/world/TileDataStack.java new file mode 100644 index 0000000..0c17ae4 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/TileDataStack.java @@ -0,0 +1,25 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.TileGenericStackWO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataStack + extends TileDataStackRO, TileGenericStackWO { + + @Override + default boolean isFull() { + return TileDataStackRO.super.isFull(); + } + + /* + * Method specialization + */ + + @Override + TileDataReference getReference(int index); + + @Override + ChunkData getChunk(); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/TileDataStackRO.java b/src/main/java/ru/windcorp/progressia/common/world/TileDataStackRO.java new file mode 100644 index 0000000..ca74bc4 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/TileDataStackRO.java @@ -0,0 +1,12 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataStackRO + extends TileGenericStackRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java index 85c6188..65f13be 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java @@ -1,216 +1,52 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - package ru.windcorp.progressia.common.world; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Objects; -import java.util.function.Consumer; import glm.vec._3.i.Vec3i; -import gnu.trove.TCollections; -import gnu.trove.map.TLongObjectMap; -import gnu.trove.map.hash.TLongObjectHashMap; -import gnu.trove.set.TLongSet; -import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.ChunkMap; -import ru.windcorp.progressia.common.world.generic.ChunkSet; -import ru.windcorp.progressia.common.world.generic.GenericWorld; -import ru.windcorp.progressia.common.world.generic.LongBasedChunkMap; +import ru.windcorp.progressia.common.world.generic.WorldGenericWO; +import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -public class WorldData - implements GenericWorld { - - private final ChunkMap chunksByPos = new LongBasedChunkMap<>( - TCollections.synchronizedMap(new TLongObjectHashMap<>()) - ); - - private final Collection chunks = Collections.unmodifiableCollection(chunksByPos.values()); - - private final TLongObjectMap entitiesById = TCollections.synchronizedMap(new TLongObjectHashMap<>()); - - private final Collection entities = Collections.unmodifiableCollection(entitiesById.valueCollection()); - - private float time = 0; - - private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); - - public WorldData() { - - } +public interface WorldData + extends WorldDataRO, WorldGenericWO { @Override - public ChunkData getChunk(Vec3i pos) { - return chunksByPos.get(pos); + default TileDataStack getTiles(Vec3i blockInWorld, BlockFace face) { + return (TileDataStack) WorldDataRO.super.getTiles(blockInWorld, face); } + /** + * Increases in-game time of this world by {@code change}. Total time is + * decreased when {@code change} is negative. + * + * @param change the amount of time to add to current world time. May be + * negative. + * @see #getTime() + */ + void advanceTime(float change); + + /* + * Method specialization + */ + @Override - public Collection getChunks() { - return chunks; - } - - public ChunkSet getLoadedChunks() { - return chunksByPos.keys(); - } - + ChunkData getChunk(Vec3i pos); + @Override - public Collection getEntities() { - return entities; - } - + Collection getChunks(); + + // TODO: rename WGRO.forEachChunk -> forEachChunkRO and define WGWO.forEachChunk + @Override - public void forEachEntity(Consumer action) { - synchronized (entitiesById) { // TODO HORRIBLY MUTILATE THE CORPSE OF - // TROVE4J so that - // gnu.trove.impl.sync.SynchronizedCollection.forEach - // is synchronized - getEntities().forEach(action); - } + default ChunkData getChunkByBlock(Vec3i blockInWorld) { + return (ChunkData) WorldDataRO.super.getChunkByBlock(blockInWorld); } - - public TLongSet getLoadedEntities() { - return entitiesById.keySet(); - } - - private void addChunkListeners(ChunkData chunk) { - getListeners().forEach(l -> l.getChunkListeners(this, chunk.getPosition(), chunk::addListener)); - } - - public synchronized void addChunk(ChunkData chunk) { - addChunkListeners(chunk); - - ChunkData previous = chunksByPos.get(chunk); - if (previous != null) { - throw new IllegalArgumentException( - String.format( - "Chunk at (%d; %d; %d) already exists", - chunk.getPosition().x, - chunk.getPosition().y, - chunk.getPosition().z - ) - ); - } - - chunksByPos.put(chunk, chunk); - - chunk.onLoaded(); - getListeners().forEach(l -> l.onChunkLoaded(this, chunk)); - } - - public synchronized void removeChunk(ChunkData chunk) { - getListeners().forEach(l -> l.beforeChunkUnloaded(this, chunk)); - chunk.beforeUnloaded(); - - chunksByPos.remove(chunk); - } - - public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { - ChunkData chunk = getChunkByBlock(blockInWorld); - if (chunk == null) - throw new IllegalCoordinatesException( - "Coordinates " - + "(" + blockInWorld.x + "; " + blockInWorld.y + "; " + blockInWorld.z + ") " - + "do not belong to a loaded chunk" - ); - - chunk.setBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null), block, notify); - } - - public EntityData getEntity(long entityId) { - return entitiesById.get(entityId); - } - - public void addEntity(EntityData entity) { - Objects.requireNonNull(entity, "entity"); - - EntityData previous = entitiesById.putIfAbsent(entity.getEntityId(), entity); - - if (previous != null) { - String message = "Cannot add entity " + entity + ": "; - - if (previous == entity) { - message += "already present"; - } else { - message += "entity with the same EntityID already present (" + previous + ")"; - } - - throw new IllegalStateException(message); - } - - getListeners().forEach(l -> l.onEntityAdded(this, entity)); - } - - public void removeEntity(long entityId) { - synchronized (entitiesById) { - EntityData entity = entitiesById.get(entityId); - - if (entity == null) { - throw new IllegalArgumentException( - "Entity with EntityID " + EntityData.formatEntityId(entityId) + " not present" - ); - } else { - removeEntity(entity); - } - } - } - - public void removeEntity(EntityData entity) { - Objects.requireNonNull(entity, "entity"); - - getListeners().forEach(l -> l.beforeEntityRemoved(this, entity)); - entitiesById.remove(entity.getEntityId()); - } - - public float getTime() { - return time; - } - - public void advanceTime(float change) { - this.time += change; - } - - public CollisionModel getCollisionModelOfBlock(Vec3i blockInWorld) { - ChunkData chunk = getChunkByBlock(blockInWorld); - if (chunk == null) - return null; - - BlockData block = chunk.getBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null)); - if (block == null) - return null; - return block.getCollisionModel(); - } - - public Collection getListeners() { - return listeners; - } - - public void addListener(WorldDataListener e) { - listeners.add(e); - } - - public void removeListener(WorldDataListener o) { - listeners.remove(o); + + @Override + default TileDataStack getTilesOrNull(Vec3i blockInWorld, BlockFace face) { + return (TileDataStack) WorldDataRO.super.getTilesOrNull(blockInWorld, face); } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java b/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java index 9211efd..0949566 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java @@ -26,11 +26,11 @@ import ru.windcorp.progressia.common.world.entity.EntityData; public interface WorldDataListener { /** - * Invoked when a new {@link ChunkData} instance is created. This method + * Invoked when a new {@link DefaultChunkData} instance is created. This method * should be used to add * {@link ChunkDataListener}s to a new chunk. When listeners are added with * this method, - * their {@link ChunkDataListener#onChunkLoaded(ChunkData) onChunkLoaded} + * their {@link ChunkDataListener#onChunkLoaded(DefaultChunkData) onChunkLoaded} * methods will be invoked. * * @param world the world instance @@ -41,7 +41,7 @@ public interface WorldDataListener { * {@link Consumer#accept(Object) accept} method * will be added to the chunk. */ - default void getChunkListeners(WorldData world, Vec3i chunk, Consumer chunkListenerSink) { + default void getChunkListeners(DefaultWorldData world, Vec3i chunk, Consumer chunkListenerSink) { } /** @@ -50,7 +50,7 @@ public interface WorldDataListener { * @param world the world instance * @param chunk the chunk that has loaded */ - default void onChunkLoaded(WorldData world, ChunkData chunk) { + default void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { } /** @@ -59,7 +59,7 @@ public interface WorldDataListener { * @param world the world instance * @param chunk the chunk that is going to be unloaded */ - default void beforeChunkUnloaded(WorldData world, ChunkData chunk) { + default void beforeChunkUnloaded(DefaultWorldData world, DefaultChunkData chunk) { } /** @@ -68,7 +68,7 @@ public interface WorldDataListener { * @param world the world instance * @param entity the entity that has been added */ - default void onEntityAdded(WorldData world, EntityData entity) { + default void onEntityAdded(DefaultWorldData world, EntityData entity) { } /** @@ -77,7 +77,7 @@ public interface WorldDataListener { * @param world the world instance * @param entity the entity that is going to be removed */ - default void beforeEntityRemoved(WorldData world, EntityData entity) { + default void beforeEntityRemoved(DefaultWorldData world, EntityData entity) { } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldDataRO.java b/src/main/java/ru/windcorp/progressia/common/world/WorldDataRO.java new file mode 100644 index 0000000..0fdfcbc --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldDataRO.java @@ -0,0 +1,29 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.WorldGenericRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface WorldDataRO + extends WorldGenericRO { + + /** + * Returns in-world time since creation. World time is zero before and + * during first tick. + *

    + * Game logic should assume that this value mostly increases uniformly. + * However, it is not guaranteed that in-world time always increments. + * + * @return time, in in-game seconds, since the world was created + */ + float getTime(); + + /** + * Gets the {@link GravityModel} used by this world. + * + * @return the gravity model + */ + GravityModel getGravityModel(); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java b/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java index e94f838..82b0543 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java @@ -15,15 +15,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.block; import ru.windcorp.progressia.common.collision.AABB; import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.generic.BlockGeneric; -public class BlockData extends Namespaced implements GenericBlock { +public class BlockData extends Namespaced implements BlockGeneric { public BlockData(String id) { super(id); diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/block/BlockDataRegistry.java index ac1934c..68b7412 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockDataRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/BlockDataRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.block; import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java b/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java deleted file mode 100644 index 9023500..0000000 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.common.world.block; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -import glm.vec._3.i.Vec3i; - -public final class BlockFace extends BlockRelation { - - public static final BlockFace TOP = new BlockFace(0, 0, +1, true, "TOP"), - BOTTOM = new BlockFace(0, 0, -1, false, "BOTTOM"), - NORTH = new BlockFace(+1, 0, 0, true, "NORTH"), - SOUTH = new BlockFace(-1, 0, 0, false, "SOUTH"), - WEST = new BlockFace(0, +1, 0, false, "WEST"), - EAST = new BlockFace(0, -1, 0, true, "EAST"); - - private static final ImmutableList ALL_FACES = ImmutableList.of(TOP, BOTTOM, NORTH, SOUTH, WEST, EAST); - - static { - link(TOP, BOTTOM); - link(NORTH, SOUTH); - link(WEST, EAST); - } - - private static final ImmutableList PRIMARY_FACES = ALL_FACES.stream().filter(BlockFace::isPrimary) - .collect(ImmutableList.toImmutableList()); - - private static final ImmutableList SECONDARY_FACES = ALL_FACES.stream().filter(BlockFace::isSecondary) - .collect(ImmutableList.toImmutableList()); - - public static final int BLOCK_FACE_COUNT = ALL_FACES.size(); - public static final int PRIMARY_BLOCK_FACE_COUNT = PRIMARY_FACES.size(); - public static final int SECONDARY_BLOCK_FACE_COUNT = SECONDARY_FACES.size(); - - public static ImmutableList getFaces() { - return ALL_FACES; - } - - public static ImmutableList getPrimaryFaces() { - return PRIMARY_FACES; - } - - public static ImmutableList getSecondaryFaces() { - return SECONDARY_FACES; - } - - private static void link(BlockFace a, BlockFace b) { - a.counterFace = b; - b.counterFace = a; - } - - public static ImmutableMap mapToFaces( - E top, - E bottom, - E north, - E south, - E east, - E west - ) { - return ImmutableMap.builderWithExpectedSize(6) - .put(TOP, top) - .put(BOTTOM, bottom) - .put(NORTH, north) - .put(SOUTH, south) - .put(EAST, east) - .put(WEST, west) - .build(); - } - - private static int nextId = 0; - - private final int id; - private final String name; - private BlockFace counterFace; - private final boolean isPrimary; - - private BlockFace(int x, int y, int z, boolean isPrimary, String name) { - super(x, y, z); - this.id = nextId++; - this.isPrimary = isPrimary; - this.name = name; - } - - public String getName() { - return name; - } - - public boolean isPrimary() { - return isPrimary; - } - - public BlockFace getPrimary() { - if (isPrimary) - return this; - else - return counterFace; - } - - public BlockFace getPrimaryAndMoveCursor(Vec3i cursor) { - if (isPrimary) - return this; - - cursor.add(getVector()); - return counterFace; - } - - public boolean isSecondary() { - return !isPrimary; - } - - public BlockFace getSecondary() { - if (isPrimary) - return counterFace; - else - return this; - } - - public BlockFace getSecondaryAndMoveCursor(Vec3i cursor) { - if (!isPrimary) - return this; - - cursor.add(getVector()); - return counterFace; - } - - public BlockFace getCounter() { - return counterFace; - } - - public BlockFace getCounterAndMoveCursor(Vec3i cursor) { - cursor.add(getVector()); - return counterFace; - } - - public int getId() { - return id; - } - - @Override - public float getEuclideanDistance() { - return 1.0f; - } - - @Override - public int getChebyshevDistance() { - return 1; - } - - @Override - public int getManhattanDistance() { - return 1; - } - - @Override - public String toString() { - return getName(); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/PacketAffectBlock.java b/src/main/java/ru/windcorp/progressia/common/world/block/PacketAffectBlock.java index 2c1c8a2..5a4a3ac 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/PacketAffectBlock.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/PacketAffectBlock.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.block; import java.io.DataInput; diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java b/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java index 55d0eb2..11e4291 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.block; import java.io.DataInput; @@ -24,7 +24,7 @@ import java.io.IOException; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class PacketSetBlock extends PacketAffectBlock { @@ -60,7 +60,7 @@ public class PacketSetBlock extends PacketAffectBlock { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { BlockData block = BlockDataRegistry.getInstance().get(getBlockId()); world.setBlock(getBlockInWorld(), block, true); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java new file mode 100644 index 0000000..e535014 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java @@ -0,0 +1,62 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextWO; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface BlockDataContext + extends BlockGenericContextWO, + WorldDataContext, + BlockDataContextRO { + + /* + * Subcontexting + */ + + @Override + default BlockDataContext pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockDataContext pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockDataContext pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default TileStackDataContext push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileDataContext push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java new file mode 100644 index 0000000..621cc9a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java @@ -0,0 +1,61 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface BlockDataContextRO + extends BlockGenericContextRO, + WorldDataContextRO { + + /* + * Subcontexting + */ + + @Override + default BlockDataContextRO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockDataContextRO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockDataContextRO pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default TileStackDataContextRO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileDataContextRO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/Context.java b/src/main/java/ru/windcorp/progressia/common/world/context/Context.java new file mode 100644 index 0000000..786e1eb --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/Context.java @@ -0,0 +1,159 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.context; + +import ru.windcorp.progressia.common.world.generic.context.AbstractContextRO; + +/** + * A cursor-like object for retrieving information about an in-game environment. + * A context object typically holds a reference to some sort of data structure + * and a cursor pointing to a location in that data structure. The exact meaning + * of "environment" and "location" is defined by extending interfaces. The terms + * relevant and implied should be understood to refer to the + * aforementioned location. + *

    + * Context objects are intended to be the primary way of interacting for in-game + * content. Wherever possible, context objects should be preferred over other + * means of accessing game structures. + *

    Context Validity

    + * Context objects may only be used while they are valid to avoid undefined + * behavior. There exists no programmatic way to determine a context's validity; + * it is the responsibility of the programmer to avoid interacting with invalid + * contexts. + *

    + * Contexts are usually acquired as method parameters. Unless stated otherwise, + * the context is valid until the invoked method returns; the only exception to + * this rule is subcontexting (see below). Consequently, contexts should never + * be stored outside their intended methods. + *

    + * In practice, context objects are typically highly volatile. They are not + * thread-safe and are often pooled and reused. + *

    + *

    Subcontexting

    + * Context objects allow subcontexting. Subcontexting is the temporary + * modification of the context object. Contexts use a stack approach to + * modification: all modifications must be reverted in the reversed order they + * were applied. + *

    + * Modification methods are usually named {@code pushXXX}. To revert + * the most recent non-reverted modification, use {@link #pop()}. As a general + * rule, a method that is given a context must always {@link #pop()} every + * change it has pushed. Failure to abide by this contract results in bugs that + * is difficult to trace. + *

    + * Although various push methods declare differing result types, the same object + * is always returned: + * + *

    + * someContext.pushXXX() == someContext
    + * 
    + * + * Therefore invoking {@link #pop()} is valid using both the original reference + * and the obtained reference. + *

    Subcontexting example

    + * Given a {@link ru.windcorp.progressia.common.world.context.BlockDataContext + * BlockDataContext} {@code a} one can process the tile stack on the top of the + * relevant block by using + * + *
    + * TileStackDataContext b = a.push(RelFace.TOP);
    + * processTileStack(b);
    + * b.pop();
    + * 
    + * + * One can improve readability by eliminating the temporary variable: + * + *
    + * processTileStack(a.push(RelFace.TOP));
    + * a.pop();
    + * 
    + * + * Notice that {@code a.pop()} and {@code b.pop()} are interchangeable. + * + * @see AbstractContextRO + * @author javapony + */ +public interface Context { + + /** + * Tests whether the environment is "real". Any actions carried out in an + * environment that is not "real" should not have any side effects outside + * of the environment. + *

    + * A typical "real" environment is the world of the client that is actually + * displayed or a world of the server that the clients actually interact + * with. An example of a non-"real" environment is a fake world used by + * developer tools to query the properties or behaviors of in-game content. + * While in-game events may well trigger global-scope actions, such as + * writing files, this may become an unintended or even harmful byproduct in + * some scenarios that are not actually linked to an actual in-game world. + *

    + * This flag should generally only be consulted before taking action through + * means other than a provided changer object. The interactions with the + * context should otherwise remain unaltered. + *

    + * When querying game content for purposes other than directly applying + * results in-game, {@code isReal()} should return {@code false}. In all + * other cases, where possible, the call should be delegated to a provided + * context object. + * + * @return {@code false} iff side effects outside the environment should be + * suppressed + */ + boolean isReal(); + + /** + * Reverts the more recent modification to this object that has not been + * reverted yet. + *

    + * Context objects may be modified temporarily with various push methods + * (see subcontexting). To revert the most + * recent non-reverted modification, use {@link #pop()}. As a general rule, + * a method that is given a context must always {@link #pop()} every change + * it has pushed. Failure to abide by this contract results in bugs that is + * difficult to trace. + *

    + * This method may be invoked using either the original reference or the + * reference provided by push method. + *

    + * This method fails with an {@link IllegalStateException} when there are no + * modifications to revert. + */ + void pop(); + + default T popAndReturn(T result) { + pop(); + return result; + } + + default boolean popAndReturn(boolean result) { + pop(); + return result; + } + + default int popAndReturn(int result) { + pop(); + return result; + } + + default float popAndReturn(float result) { + pop(); + return result; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java new file mode 100644 index 0000000..b424b2f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java @@ -0,0 +1,44 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.context; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.TileGenericContextWO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataContext + extends TileGenericContextWO, + TileStackDataContext, + TileDataContextRO { + + /* + * Subcontexting + */ + + @Override + default TileDataContext pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileDataContext pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java new file mode 100644 index 0000000..f6979e2 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java @@ -0,0 +1,43 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.context; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.TileGenericContextRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataContextRO + extends TileGenericContextRO, + TileStackDataContextRO { + + /* + * Subcontexting + */ + + @Override + default TileDataContextRO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileDataContextRO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java new file mode 100644 index 0000000..1751a50 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java @@ -0,0 +1,49 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.context; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.TileStackGenericContextWO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileStackDataContext + extends TileStackGenericContextWO, + BlockDataContext, + TileStackDataContextRO { + + /* + * Subcontexting + */ + + @Override + default TileDataContext push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackDataContext pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackDataContext pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java new file mode 100644 index 0000000..bcdb948 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java @@ -0,0 +1,48 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.context; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.TileStackGenericContextRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileStackDataContextRO + extends TileStackGenericContextRO, + BlockDataContextRO { + + /* + * Subcontexting + */ + + @Override + default TileDataContextRO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackDataContextRO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackDataContextRO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java new file mode 100644 index 0000000..9dcb0ae --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java @@ -0,0 +1,54 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextWO; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface WorldDataContext + extends WorldGenericContextWO, + WorldDataContextRO { + + /** + * Increases in-game time of this world by {@code change}. Total time is + * decreased when {@code change} is negative. + * + * @param change the amount of time to add to current world time. May be + * negative. + * @see #getTime() + */ + void advanceTime(float change); + + /* + * Subcontexting + */ + + @Override + BlockDataContext push(Vec3i location); + + @Override + TileStackDataContext push(Vec3i location, RelFace face); + + @Override + TileDataContext push(Vec3i location, RelFace face, int layer); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java new file mode 100644 index 0000000..be037bf --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java @@ -0,0 +1,62 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface WorldDataContextRO extends WorldGenericContextRO { + + /** + * Returns in-world time since creation. World time is zero before and + * during first tick. + *

    + * Game logic should assume that this value mostly increases uniformly. + * However, it is not guaranteed that in-world time always increments. + * + * @return time, in in-game seconds, since the world was created + */ + float getTime(); + + /** + * Gets the {@link GravityModel} used by this world. + * + * @return the gravity model + */ + GravityModel getGravityModel(); + + /* + * Subcontexting + */ + + @Override + BlockDataContextRO push(Vec3i location); + + @Override + TileStackDataContextRO push(Vec3i location, RelFace face); + + @Override + TileDataContextRO push(Vec3i location, RelFace face, int layer); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java index 7b3325c..bc00974 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java @@ -15,28 +15,33 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.entity; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.util.Objects; -import glm.vec._2.Vec2; +import glm.mat._3.Mat3; import glm.vec._3.Vec3; import ru.windcorp.jputil.chars.StringUtil; +import ru.windcorp.progressia.common.collision.AABBRotator; import ru.windcorp.progressia.common.collision.Collideable; import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.state.StatefulObject; -import ru.windcorp.progressia.common.world.generic.GenericEntity; +import ru.windcorp.progressia.common.util.Matrices; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.AbsFace; -public class EntityData extends StatefulObject implements Collideable, GenericEntity { +public class EntityData extends StatefulObject implements Collideable, EntityGeneric { private final Vec3 position = new Vec3(); private final Vec3 velocity = new Vec3(); - private final Vec2 direction = new Vec2(); + private final Vec3 lookingAt = new Vec3(1, 0, 0); + private final Vec3 upVector = new Vec3(0, 0, 1); /** * The unique {@code long} value guaranteed to never be assigned to an @@ -48,6 +53,7 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn private long entityId; private CollisionModel collisionModel = null; + private CollisionModel rotatedCollisionModel = null; private double age = 0; @@ -79,22 +85,7 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn this.velocity.set(velocity); } - public Vec2 getDirection() { - return direction; - } - - public void setDirection(Vec2 direction) { - this.direction.set(direction.x, direction.y); - } - - public float getYaw() { - return getDirection().x; - } - - public float getPitch() { - return getDirection().y; - } - + @Override public long getEntityId() { return entityId; } @@ -120,11 +111,16 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn @Override public CollisionModel getCollisionModel() { + return rotatedCollisionModel; + } + + public CollisionModel getOriginalCollisionModel() { return collisionModel; } public void setCollisionModel(CollisionModel collisionModel) { this.collisionModel = collisionModel; + this.rotatedCollisionModel = AABBRotator.rotate(this::getUpFace, this::getPosition, collisionModel); } @Override @@ -152,16 +148,166 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn getVelocity().add(velocityChange); } - public Vec3 getLookingAtVector(Vec3 output) { - output.set( - Math.cos(getPitch()) * Math.cos(getYaw()), - Math.cos(getPitch()) * Math.sin(getYaw()), - -Math.sin(getPitch()) - ); + public Vec3 getLookingAt() { + return lookingAt; + } + public void setLookingAt(Vec3 lookingAt) { + float lengthSq = lookingAt.x * lookingAt.x + lookingAt.y * lookingAt.y + lookingAt.z * lookingAt.z; + if (lengthSq == 1) { + this.lookingAt.set(lookingAt); + } else if (lengthSq == 0) { + throw new IllegalArgumentException("lookingAt is zero-length"); + } else if (!Float.isFinite(lengthSq)) { + throw new IllegalArgumentException("lookingAt is not finite: " + lookingAt); + } else { + float length = (float) Math.sqrt(lengthSq); + this.lookingAt.set( + lookingAt.x / length, + lookingAt.y / length, + lookingAt.z / length + ); + } + } + + public Vec3 getUpVector() { + return upVector; + } + + public AbsFace getUpFace() { + return AbsFace.roundToFace(getUpVector()); + } + + /** + * Sets this entity's up vector without updating looking at-vector. + * + * @param upVector the Vec3 to copy up vector from + * @see #changeUpVector(Vec3) + */ + public void setUpVector(Vec3 upVector) { + float lengthSq = upVector.x * upVector.x + upVector.y * upVector.y + upVector.z * upVector.z; + if (lengthSq == 1) { + this.upVector.set(upVector); + } else if (lengthSq == 0) { + throw new IllegalArgumentException("upVector is zero-length"); + } else if (!Float.isFinite(lengthSq)) { + throw new IllegalArgumentException("upVector is not finite: " + upVector); + } else { + float length = (float) Math.sqrt(lengthSq); + this.upVector.set( + upVector.x / length, + upVector.y / length, + upVector.z / length + ); + } + } + + /** + * Computes the forward vector of this entity. An entity's forward vector is + * defined as a normalized projection of the looking at-vector onto the + * plane perpendicular to up vector, or {@code (NaN; NaN; NaN)} if looking + * at-vector is parallel to the up vector. + * + * @param output a {@link Vec3} where the result is stored. May be + * {@code null}. + * @return the computed forward vector or {@code (NaN; NaN; NaN)} + */ + public Vec3 getForwardVector(Vec3 output) { + if (output == null) + output = new Vec3(); + output.set(getUpVector()).mul(-getUpVector().dot(getLookingAt())).add(getLookingAt()).normalize(); return output; } + public double getPitch() { + return -Math.acos(getLookingAt().dot(getUpVector())) + Math.PI / 2; + } + + /** + * Updates this entity's up vector and alters looking at-vector to match the + * rotation of the up vector. + *

    + * This method assumes that the up vector has changed due to rotation around + * some axis. The axis and the angle are computed, after which the same + * rotation is applied to the looking at-vector. + * + * @param newUpVector the Vec3 to copy up vector from. May be equal to + * current up vector + * @see #setLookingAt(Vec3) + */ + public void changeUpVector(Vec3 newUpVector) { + Objects.requireNonNull(newUpVector, "newUpVector"); + + Vec3 u0 = upVector; + Vec3 u1 = newUpVector; + + if (u1.x == 0 && u1.y == 0 && u1.z == 0) { + // Entering weightlessness, not changing anything + return; + } + + if (u0.x == u1.x && u0.y == u1.y && u0.z == u1.z) { + // Nothing changed + return; + } + + if (u0.x == -u1.x && u0.y == -u1.y && u0.z == -u1.z) { + // Welp, don't do anything stupid then + upVector.set(newUpVector); + return; + } + + float u1LengthSq = u1.x*u1.x + u1.y*u1.y + u1.z*u1.z; + float u1Length = 1; + + if (!Float.isFinite(u1LengthSq)) { + throw new IllegalArgumentException("newUpVector is not finite: " + newUpVector); + } else if (u1LengthSq != 1) { + u1Length = (float) Math.sqrt(u1LengthSq); + } + + // u0 and u1 are now both definitely two different usable vectors + + if (rotateLookingAtToMatchUpVectorRotation(u0, u1, u1Length, lookingAt)) { + return; + } + + upVector.set(newUpVector).div(u1Length); + } + + private static boolean rotateLookingAtToMatchUpVectorRotation(Vec3 u0, Vec3 u1, float u1Length, Vec3 lookingAt) { + // Determine rotation parameters + Vec3 axis = u0.cross_(u1); + float cos = u0.dot(u1) / u1Length; + float sin = axis.length() / u1Length; + + if (sin == 0) { + return true; + } + + axis.div(sin * u1Length); // normalize axis + + float x = axis.x; + float y = axis.y; + float z = axis.z; + + Mat3 matrix = Matrices.grab3(); + + // Don't format. @formatter:off + matrix.set( + cos + (1 - cos)*x*x, (1 - cos)*y*x + sin*z, (1 - cos)*z*x - sin*y, + (1 - cos)*x*y - sin*z, cos + (1 - cos)*y*y, (1 - cos)*z*y + sin*x, + (1 - cos)*x*z + sin*y, (1 - cos)*y*z - sin*x, cos + (1 - cos)*z*z + ); + // @formatter:on + + matrix.mul_(lookingAt); // bug in jglm, .mul() and .mul_() are swapped + + Matrices.release(matrix); + + return false; + } + @Override public String toString() { return new StringBuilder(super.toString()) @@ -189,8 +335,13 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn output.writeFloat(getVelocity().y); output.writeFloat(getVelocity().z); - output.writeFloat(getDirection().x); - output.writeFloat(getDirection().y); + output.writeFloat(getLookingAt().x); + output.writeFloat(getLookingAt().y); + output.writeFloat(getLookingAt().z); + + output.writeFloat(getUpVector().x); + output.writeFloat(getUpVector().y); + output.writeFloat(getUpVector().z); super.write(output, context); } @@ -209,14 +360,22 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn input.readFloat() ); - Vec2 direction = new Vec2( + Vec3 lookingAt = new Vec3( + input.readFloat(), + input.readFloat(), + input.readFloat() + ); + + Vec3 upVector = new Vec3( + input.readFloat(), input.readFloat(), input.readFloat() ); setPosition(position); setVelocity(velocity); - setDirection(direction); + setLookingAt(lookingAt); + setUpVector(upVector); super.read(input, context); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataRegistry.java index 26f219d..34271ae 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.entity; import ru.windcorp.progressia.common.state.StatefulObjectRegistry; diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java index f3bf792..b571fba 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.entity; import java.io.DataInput; @@ -24,7 +24,7 @@ import java.io.IOException; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.PacketAffectWorld; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class PacketAffectEntity extends PacketAffectWorld { @@ -53,7 +53,7 @@ public class PacketAffectEntity extends PacketAffectWorld { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { world.removeEntity(this.entityId); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java index d09b0f3..2d42a7a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.entity; import java.io.DataInput; @@ -26,7 +26,7 @@ import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.util.DataBuffer; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class PacketChangeEntity extends PacketAffectEntity { @@ -68,7 +68,7 @@ public class PacketChangeEntity extends PacketAffectEntity { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { EntityData entity = world.getEntity(getEntityId()); if (entity == null) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java index 06dfc12..a0ceee2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.entity; import java.io.DataInput; @@ -23,7 +23,7 @@ import java.io.DataOutput; import java.io.IOException; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class PacketRevokeEntity extends PacketAffectEntity { @@ -51,7 +51,7 @@ public class PacketRevokeEntity extends PacketAffectEntity { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { world.removeEntity(getEntityId()); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java index 6604d4a..71e903f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.entity; import java.io.DataInput; @@ -26,7 +26,7 @@ import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.util.DataBuffer; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class PacketSendEntity extends PacketAffectEntity { @@ -85,7 +85,7 @@ public class PacketSendEntity extends PacketAffectEntity { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { EntityData entity = EntityDataRegistry.getInstance().create(getEntityTypeId()); entity.setEntityId(getEntityId()); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTile.java b/src/main/java/ru/windcorp/progressia/common/world/generic/BlockGeneric.java similarity index 96% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericTile.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/BlockGeneric.java index e35aec2..1ccd022 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/BlockGeneric.java @@ -15,10 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.generic; -public interface GenericTile { +public interface BlockGeneric { String getId(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericRO.java new file mode 100644 index 0000000..cd648c5 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericRO.java @@ -0,0 +1,311 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.generic; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import glm.Glm; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.AxisRotations; +import ru.windcorp.progressia.common.world.rels.BlockFace; + +/** + * An unmodifiable chunk representation. Per default, it is usually one of + * {@link ru.windcorp.progressia.common.world.DefaultChunkData ChunkData}, + * {@link ru.windcorp.progressia.client.world.ChunkRender ChunkRender} or + * {@link ru.windcorp.progressia.server.world.DefaultChunkLogic ChunkLogic}, but this + * interface may be implemented differently for various reasons. + *

    + * A generic chunk contains {@linkplain BlockGeneric blocks} and + * {@linkplain TileGenericStackRO tile stacks} and is characterized by its + * location. It also bears a discrete up direction. Note that no + * {@linkplain WorldGenericRO world} object is directly accessible through this + * interface. + *

    + * This interface defines the most common methods for examining a chunk and + * implements many of them as default methods. It also contains several static + * methods useful when dealing with chunks. {@code GenericChunk} does not + * provide a way to modify a chunk; use {@link ChunkGenericWO} methods + * when applicable. + * + * @param a reference to itself (required to properly reference a + * {@link TileGenericStackRO}) + * @param block type + * @param tile type + * @param tile stack type + * @author javapony + */ +// @formatter:off +public interface ChunkGenericRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO +> { +// @formatter:on + + /** + * The count of blocks in a side of a chunk. This is guaranteed to be a + * power of two. This is always equal to {@link Coordinates#CHUNK_SIZE}. + */ + public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; + + /* + * Abstract methods + */ + + /** + * Returns the position of this chunk in {@linkplain Coordinates#chunk + * coordinates of chunk}. The returned object must not be modified. + * + * @return this chunk's position + */ + Vec3i getPosition(); + + /** + * Returns the discrete up direction for this chunk. + * + * @return this chunk's discrete up direction + */ + AbsFace getUp(); + + /** + * Retrieves the block at the location specified by its + * {@linkplain Coordinates#blockInChunk chunk coordinates}. During chunk + * generation it may be {@code null}. + * + * @param blockInChunk local coordinates of the block to fetch + * @return the block at the requested location or {@code null}. + */ + B getBlock(Vec3i blockInChunk); + + TS getTiles(Vec3i blockInChunk, BlockFace face); + + boolean hasTiles(Vec3i blockInChunk, BlockFace face); + + default Vec3i resolve(Vec3i relativeCoords, Vec3i output) { + return GenericChunks.resolve(relativeCoords, getUp(), output); + } + + default Vec3i relativize(Vec3i absoluteCoords, Vec3i output) { + return GenericChunks.relativize(absoluteCoords, getUp(), output); + } + + default B getBlockRel(Vec3i relativeBlockInChunk) { + Vec3i absoluteBlockInChunk = Vectors.grab3i(); + resolve(relativeBlockInChunk, absoluteBlockInChunk); + B result = getBlock(absoluteBlockInChunk); + Vectors.release(absoluteBlockInChunk); + return result; + } + + default TS getTilesRel(Vec3i relativeBlockInChunk, BlockFace face) { + Vec3i absoluteBlockInChunk = Vectors.grab3i(); + resolve(relativeBlockInChunk, absoluteBlockInChunk); + TS result = getTiles(absoluteBlockInChunk, face); + Vectors.release(absoluteBlockInChunk); + return result; + } + + default boolean hasTilesRel(Vec3i relativeBlockInChunk, BlockFace face) { + Vec3i absoluteBlockInChunk = Vectors.grab3i(); + resolve(relativeBlockInChunk, absoluteBlockInChunk); + boolean result = hasTiles(absoluteBlockInChunk, face); + Vectors.release(absoluteBlockInChunk); + return result; + } + + default int getX() { + return getPosition().x; + } + + default int getMinX() { + return Coordinates.getInWorld(getX(), 0); + } + + default int getMaxX() { + return Coordinates.getInWorld(getX(), BLOCKS_PER_CHUNK - 1); + } + + default int getY() { + return getPosition().y; + } + + default int getMinY() { + return Coordinates.getInWorld(getY(), 0); + } + + default int getMaxY() { + return Coordinates.getInWorld(getY(), BLOCKS_PER_CHUNK - 1); + } + + default int getZ() { + return getPosition().z; + } + + default int getMinZ() { + return Coordinates.getInWorld(getZ(), 0); + } + + default int getMaxZ() { + return Coordinates.getInWorld(getZ(), BLOCKS_PER_CHUNK - 1); + } + + default Vec3i getMinBIW(Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(getMinX(), getMinY(), getMinZ()); + + return output; + } + + default Vec3i getMaxBIW(Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(getMaxX(), getMaxY(), getMaxZ()); + + return output; + } + + default Vec3i getMinBIWRel(Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + Vec3i absMin = getMinBIW(Vectors.grab3i()); + Vec3i absMax = getMaxBIW(Vectors.grab3i()); + + AxisRotations.relativize(absMin, getUp(), absMin); + AxisRotations.relativize(absMax, getUp(), absMax); + + Glm.min(absMin, absMax, output); + + Vectors.release(absMax); + Vectors.release(absMin); + + return output; + } + + default Vec3i getMaxBIWRel(Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + Vec3i absMin = getMinBIW(Vectors.grab3i()); + Vec3i absMax = getMaxBIW(Vectors.grab3i()); + + AxisRotations.relativize(absMin, getUp(), absMin); + AxisRotations.relativize(absMax, getUp(), absMax); + + Glm.max(absMin, absMax, output); + + Vectors.release(absMax); + Vectors.release(absMin); + + return output; + } + + default boolean containsBiW(Vec3i blockInWorld) { + return GenericChunks.testBiC(blockInWorld, this, GenericChunks::containsBiC); + } + + default boolean isSurfaceBiW(Vec3i blockInWorld) { + return GenericChunks.testBiC(blockInWorld, this, GenericChunks::isSurfaceBiC); + } + + default boolean isEdgeBiW(Vec3i blockInWorld) { + return GenericChunks.testBiC(blockInWorld, this, GenericChunks::isEdgeBiC); + } + + default boolean isVertexBiW(Vec3i blockInWorld) { + return GenericChunks.testBiC(blockInWorld, this, GenericChunks::isVertexBiC); + } + + default void forEachBiW(Consumer action) { + int minX = Coordinates.getInWorld(getX(), 0); + int minY = Coordinates.getInWorld(getY(), 0); + int minZ = Coordinates.getInWorld(getZ(), 0); + + VectorUtil.iterateCuboid( + minX, + minY, + minZ, + minX + BLOCKS_PER_CHUNK, + minY + BLOCKS_PER_CHUNK, + minZ + BLOCKS_PER_CHUNK, + action + ); + } + + default TS getTilesOrNull(Vec3i blockInChunk, BlockFace face) { + if (hasTiles(blockInChunk, face)) { + return getTiles(blockInChunk, face); + } + + return null; + } + + default TS getTilesOrNullRel(Vec3i relativeBlockInChunk, BlockFace face) { + Vec3i absoluteBlockInChunk = Vectors.grab3i(); + resolve(relativeBlockInChunk, absoluteBlockInChunk); + + TS result; + + if (hasTiles(absoluteBlockInChunk, face)) { + result = getTiles(absoluteBlockInChunk, face); + } else { + result = null; + } + + Vectors.release(absoluteBlockInChunk); + + return result; + } + + default void forEachTileStack(Consumer action) { + GenericChunks.forEachBiC(blockInChunk -> { + for (AbsFace face : AbsFace.getFaces()) { + TS stack = getTilesOrNull(blockInChunk, face); + if (stack == null) + continue; + action.accept(stack); + } + }); + } + + /** + * Iterates over all tiles in this chunk. + * + * @param action the action to perform + */ + default void forEachTile(BiConsumer action) { + forEachTileStack(stack -> stack.forEach(tileData -> action.accept(stack, tileData))); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericWO.java new file mode 100644 index 0000000..1005454 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericWO.java @@ -0,0 +1,37 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.BlockFace; + +// @formatter:off +public interface ChunkGenericWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO +> { +// @formatter:on + + void setBlock(Vec3i posInChunk, B block, boolean notify); + + TS getTiles(Vec3i blockInChunk, BlockFace face); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java index 6c35781..695ba91 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java @@ -77,27 +77,27 @@ public interface ChunkMap { // TODO implement (int, int, int) and GenericChunk versions of all of the // above - default boolean containsChunk(GenericChunk chunk) { + default boolean containsChunk(ChunkGenericRO chunk) { return containsKey(chunk.getPosition()); } - default V get(GenericChunk chunk) { + default V get(ChunkGenericRO chunk) { return get(chunk.getPosition()); } - default V put(GenericChunk chunk, V obj) { + default V put(ChunkGenericRO chunk, V obj) { return put(chunk.getPosition(), obj); } - default V remove(GenericChunk chunk) { + default V remove(ChunkGenericRO chunk) { return remove(chunk.getPosition()); } - default V getOrDefault(GenericChunk chunk, V def) { + default V getOrDefault(ChunkGenericRO chunk, V def) { return containsChunk(chunk) ? def : get(chunk); } - default > V compute( + default > V compute( C chunk, BiFunction remappingFunction ) { @@ -128,8 +128,8 @@ public interface ChunkMap { void forEach(BiConsumer action); - default > void forEachIn( - GenericWorld world, + default > void forEachIn( + WorldGenericRO world, BiConsumer action ) { forEach((pos, value) -> { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java new file mode 100644 index 0000000..658f9ea --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java @@ -0,0 +1,261 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.generic; + +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import glm.vec._3.i.Vec3i; +import gnu.trove.map.hash.TLongObjectHashMap; + +public class ChunkMaps { + + public static ChunkMap newHashMap() { + return new LongBasedChunkMap(new TLongObjectHashMap()); + } + + public static ChunkMap newSyncHashMap(Object mutex) { + return new SynchronizedChunkMap(new LongBasedChunkMap(new TLongObjectHashMap()), mutex); + } + + public static ChunkMap newSyncHashMap() { + return newSyncHashMap(null); + } + + @SuppressWarnings("unchecked") + public static ChunkMap empty() { + return (ChunkMap) EMPTY_MAP; + } + + private ChunkMaps() { + } + + private final static ChunkMap EMPTY_MAP = new ChunkMap() { + + @Override + public int size() { + return 0; + } + + @Override + public boolean containsKey(Vec3i pos) { + return false; + } + + @Override + public Object get(Vec3i pos) { + return null; + } + + @Override + public Object put(Vec3i pos, Object obj) { + throw new UnsupportedOperationException(); + } + + @Override + public Object remove(Vec3i pos) { + throw new UnsupportedOperationException(); + } + + @Override + public Collection values() { + return Collections.emptyList(); + } + + @Override + public ChunkSet keys() { + return ChunkSets.empty(); + } + + @Override + public boolean removeIf(BiPredicate condition) { + return false; + } + + @Override + public void forEach(BiConsumer action) { + // Do nothing + } + + }; + + private static class SynchronizedChunkMap implements ChunkMap { + + private final ChunkMap parent; + private final Object mutex; + + public SynchronizedChunkMap(ChunkMap parent, Object mutex) { + Objects.requireNonNull(parent, "parent"); + this.parent = parent; + + this.mutex = mutex == null ? this : mutex; + } + + @Override + public int size() { + synchronized (mutex) { + return parent.size(); + } + } + + @Override + public boolean isEmpty() { + synchronized (mutex) { + return parent.isEmpty(); + } + } + + @Override + public boolean containsKey(Vec3i pos) { + synchronized (mutex) { + return parent.containsKey(pos); + } + } + + @Override + public V get(Vec3i pos) { + synchronized (mutex) { + return parent.get(pos); + } + } + + @Override + public V put(Vec3i pos, V obj) { + synchronized (mutex) { + return parent.put(pos, obj); + } + } + + @Override + public V remove(Vec3i pos) { + synchronized (mutex) { + return parent.remove(pos); + } + } + + @Override + public boolean containsValue(V value) { + synchronized (mutex) { + return parent.containsValue(value); + } + } + + @Override + public V getOrDefault(Vec3i pos, V def) { + synchronized (mutex) { + return parent.getOrDefault(pos, def); + } + } + + @Override + public V compute(Vec3i pos, BiFunction remappingFunction) { + synchronized (mutex) { + return parent.compute(pos, remappingFunction); + } + } + + @Override + public boolean containsChunk(ChunkGenericRO chunk) { + synchronized (mutex) { + return parent.containsChunk(chunk); + } + } + + @Override + public V get(ChunkGenericRO chunk) { + synchronized (mutex) { + return parent.get(chunk); + } + } + + @Override + public V put(ChunkGenericRO chunk, V obj) { + synchronized (mutex) { + return parent.put(chunk, obj); + } + } + + @Override + public V remove(ChunkGenericRO chunk) { + synchronized (mutex) { + return parent.remove(chunk); + } + } + + @Override + public V getOrDefault(ChunkGenericRO chunk, V def) { + synchronized (mutex) { + return parent.getOrDefault(chunk, def); + } + } + + @Override + public > V compute( + C chunk, + BiFunction remappingFunction + ) { + synchronized (mutex) { + return parent.compute(chunk, remappingFunction); + } + } + + @Override + public Collection values() { + synchronized (mutex) { + return parent.values(); + } + } + + @Override + public ChunkSet keys() { + synchronized (mutex) { + return parent.keys(); + } + } + + @Override + public boolean removeIf(BiPredicate condition) { + synchronized (mutex) { + return parent.removeIf(condition); + } + } + + @Override + public void forEach(BiConsumer action) { + synchronized (mutex) { + parent.forEach(action); + } + } + + @Override + public > void forEachIn( + WorldGenericRO world, + BiConsumer action + ) { + synchronized (mutex) { + parent.forEachIn(world, action); + } + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java index 73c2267..9b75d3c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java @@ -56,6 +56,7 @@ public interface ChunkSet extends Iterable { default boolean contains(int x, int y, int z) { Vec3i v = Vectors.grab3i(); + v.set(x, y, z); boolean result = contains(v); Vectors.release(v); return result; @@ -63,6 +64,7 @@ public interface ChunkSet extends Iterable { default boolean add(int x, int y, int z) { Vec3i v = Vectors.grab3i(); + v.set(x, y, z); boolean result = add(v); Vectors.release(v); return result; @@ -70,25 +72,26 @@ public interface ChunkSet extends Iterable { default boolean remove(int x, int y, int z) { Vec3i v = Vectors.grab3i(); + v.set(x, y, z); boolean result = remove(v); Vectors.release(v); return result; } - default boolean contains(GenericChunk chunk) { + default boolean contains(ChunkGenericRO chunk) { return contains(chunk.getPosition()); } - default boolean add(GenericChunk chunk) { + default boolean add(ChunkGenericRO chunk) { return add(chunk.getPosition()); } - default boolean remove(GenericChunk chunk) { + default boolean remove(ChunkGenericRO chunk) { return remove(chunk.getPosition()); } - default > void forEachIn( - GenericWorld world, + default > void forEachIn( + WorldGenericRO world, Consumer action ) { forEach(position -> { @@ -207,7 +210,7 @@ public interface ChunkSet extends Iterable { } } - default boolean containsAllChunks(Iterable> chunks) { + default boolean containsAllChunks(Iterable> chunks) { boolean[] hasMissing = new boolean[] { false }; chunks.forEach(c -> { @@ -219,7 +222,7 @@ public interface ChunkSet extends Iterable { return hasMissing[0]; } - default boolean containsAnyChunks(Iterable> chunks) { + default boolean containsAnyChunks(Iterable> chunks) { boolean[] hasPresent = new boolean[] { false }; chunks.forEach(c -> { @@ -231,11 +234,11 @@ public interface ChunkSet extends Iterable { return hasPresent[0]; } - default void addAllChunks(Iterable> chunks) { + default void addAllChunks(Iterable> chunks) { chunks.forEach(this::add); } - default void removeAllChunks(Iterable> chunks) { + default void removeAllChunks(Iterable> chunks) { chunks.forEach(this::remove); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java index 93413e4..8123cbc 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java @@ -198,29 +198,29 @@ public class ChunkSets { } @Override - public boolean contains(GenericChunk chunk) { + public boolean contains(ChunkGenericRO chunk) { synchronized (mutex) { return parent.contains(chunk); } } @Override - public boolean add(GenericChunk chunk) { + public boolean add(ChunkGenericRO chunk) { synchronized (mutex) { return parent.add(chunk); } } @Override - public boolean remove(GenericChunk chunk) { + public boolean remove(ChunkGenericRO chunk) { synchronized (mutex) { return parent.remove(chunk); } } @Override - public > void forEachIn( - GenericWorld world, + public > void forEachIn( + WorldGenericRO world, Consumer action ) { synchronized (mutex) { @@ -320,28 +320,28 @@ public class ChunkSets { } @Override - public boolean containsAllChunks(Iterable> chunks) { + public boolean containsAllChunks(Iterable> chunks) { synchronized (mutex) { return parent.containsAllChunks(chunks); } } @Override - public boolean containsAnyChunks(Iterable> chunks) { + public boolean containsAnyChunks(Iterable> chunks) { synchronized (mutex) { return parent.containsAnyChunks(chunks); } } @Override - public void addAllChunks(Iterable> chunks) { + public void addAllChunks(Iterable> chunks) { synchronized (mutex) { parent.addAllChunks(chunks); } } @Override - public void removeAllChunks(Iterable> chunks) { + public void removeAllChunks(Iterable> chunks) { synchronized (mutex) { parent.removeAllChunks(chunks); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java b/src/main/java/ru/windcorp/progressia/common/world/generic/EntityGeneric.java similarity index 95% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/EntityGeneric.java index c15bd39..eda5bc6 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/EntityGeneric.java @@ -15,16 +15,18 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.generic; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -public interface GenericEntity { +public interface EntityGeneric { String getId(); + + long getEntityId(); Vec3 getPosition(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java deleted file mode 100644 index 656304f..0000000 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.common.world.generic; - -import java.util.function.Consumer; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.VectorUtil; -import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public interface GenericChunk, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack> { - - public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; - - Vec3i getPosition(); - - B getBlock(Vec3i blockInChunk); - - TS getTiles(Vec3i blockInChunk, BlockFace face); - - boolean hasTiles(Vec3i blockInChunk, BlockFace face); - - default int getX() { - return getPosition().x; - } - - default int getMinX() { - return Coordinates.getInWorld(getX(), 0); - } - - default int getMaxX() { - return Coordinates.getInWorld(getX(), BLOCKS_PER_CHUNK - 1); - } - - default int getY() { - return getPosition().y; - } - - default int getMinY() { - return Coordinates.getInWorld(getY(), 0); - } - - default int getMaxY() { - return Coordinates.getInWorld(getY(), BLOCKS_PER_CHUNK - 1); - } - - default int getZ() { - return getPosition().z; - } - - default int getMinZ() { - return Coordinates.getInWorld(getZ(), 0); - } - - default int getMaxZ() { - return Coordinates.getInWorld(getZ(), BLOCKS_PER_CHUNK - 1); - } - - default boolean containsBiC(Vec3i blockInChunk) { - return blockInChunk.x >= 0 && blockInChunk.x < BLOCKS_PER_CHUNK && - blockInChunk.y >= 0 && blockInChunk.y < BLOCKS_PER_CHUNK && - blockInChunk.z >= 0 && blockInChunk.z < BLOCKS_PER_CHUNK; - } - - default boolean containsBiW(Vec3i blockInWorld) { - Vec3i v = Vectors.grab3i(); - - v = Coordinates.getInWorld(getPosition(), Vectors.ZERO_3i, v); - v = blockInWorld.sub(v, v); - - boolean result = containsBiC(v); - - Vectors.release(v); - return result; - } - - default boolean isSurfaceBiC(Vec3i blockInChunk) { - int hits = 0; - - if (Coordinates.isOnChunkBorder(blockInChunk.x)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.y)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.z)) hits++; - - return hits >= 1; - } - - default boolean isSurfaceBiW(Vec3i blockInWorld) { - Vec3i v = Vectors.grab3i(); - - v = Coordinates.getInWorld(getPosition(), Vectors.ZERO_3i, v); - v = blockInWorld.sub(v, v); - - boolean result = isSurfaceBiC(v); - - Vectors.release(v); - return result; - } - - default boolean isEdgeBiC(Vec3i blockInChunk) { - int hits = 0; - - if (Coordinates.isOnChunkBorder(blockInChunk.x)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.y)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.z)) hits++; - - return hits >= 2; - } - - default boolean isEdgeBiW(Vec3i blockInWorld) { - Vec3i v = Vectors.grab3i(); - - v = Coordinates.getInWorld(getPosition(), Vectors.ZERO_3i, v); - v = blockInWorld.sub(v, v); - - boolean result = isEdgeBiC(v); - - Vectors.release(v); - return result; - } - - default boolean isVertexBiC(Vec3i blockInChunk) { - int hits = 0; - - if (Coordinates.isOnChunkBorder(blockInChunk.x)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.y)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.z)) hits++; - - return hits == 3; - } - - default boolean isVertexBiW(Vec3i blockInWorld) { - Vec3i v = Vectors.grab3i(); - - v = Coordinates.getInWorld(getPosition(), Vectors.ZERO_3i, v); - v = blockInWorld.sub(v, v); - - boolean result = isVertexBiC(v); - - Vectors.release(v); - return result; - } - - default void forEachBiC(Consumer action) { - VectorUtil.iterateCuboid( - 0, - 0, - 0, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - action - ); - } - - default void forEachBiW(Consumer action) { - VectorUtil.iterateCuboid( - Coordinates.getInWorld(getX(), 0), - Coordinates.getInWorld(getY(), 0), - Coordinates.getInWorld(getZ(), 0), - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - action - ); - } - - default TS getTilesOrNull(Vec3i blockInChunk, BlockFace face) { - if (hasTiles(blockInChunk, face)) { - return getTiles(blockInChunk, face); - } - - return null; - } - -} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java new file mode 100644 index 0000000..83ba89a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java @@ -0,0 +1,119 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic; + +import java.util.function.Consumer; +import java.util.function.Predicate; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.AxisRotations; + +public class GenericChunks { + + public static Vec3i resolve(Vec3i relativeCoords, AbsFace up, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + final int offset = ChunkGenericRO.BLOCKS_PER_CHUNK - 1; + + output.set(relativeCoords.x, relativeCoords.y, relativeCoords.z); + output.mul(2).sub(offset); + + AxisRotations.resolve(output, up, output); + + output.add(offset).div(2); + + return output; + } + + public static Vec3i relativize(Vec3i absoluteCoords, AbsFace up, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + final int offset = ChunkGenericRO.BLOCKS_PER_CHUNK - 1; + + output.set(absoluteCoords.x, absoluteCoords.y, absoluteCoords.z); + output.mul(2).sub(offset); + + AxisRotations.relativize(output, up, output); + + output.add(offset).div(2); + + return output; + } + + private static int getBorderHits(Vec3i blockInChunk) { + int hits = 0; + + if (Coordinates.isOnChunkBorder(blockInChunk.x)) hits++; + if (Coordinates.isOnChunkBorder(blockInChunk.y)) hits++; + if (Coordinates.isOnChunkBorder(blockInChunk.z)) hits++; + + return hits; + } + + static boolean testBiC(Vec3i blockInWorld, ChunkGenericRO chunk, Predicate test) { + Vec3i v = Vectors.grab3i(); + + v = Coordinates.getInWorld(chunk.getPosition(), Vectors.ZERO_3i, v); + v = blockInWorld.sub(v, v); + + boolean result = test.test(v); + + Vectors.release(v); + + return result; + } + + public static boolean containsBiC(Vec3i blockInChunk) { + return blockInChunk.x >= 0 && blockInChunk.x < ChunkGenericRO.BLOCKS_PER_CHUNK && + blockInChunk.y >= 0 && blockInChunk.y < ChunkGenericRO.BLOCKS_PER_CHUNK && + blockInChunk.z >= 0 && blockInChunk.z < ChunkGenericRO.BLOCKS_PER_CHUNK; + } + + public static boolean isSurfaceBiC(Vec3i blockInChunk) { + return GenericChunks.getBorderHits(blockInChunk) >= 1; + } + + public static boolean isEdgeBiC(Vec3i blockInChunk) { + return GenericChunks.getBorderHits(blockInChunk) >= 2; + } + + public static boolean isVertexBiC(Vec3i blockInChunk) { + return GenericChunks.getBorderHits(blockInChunk) == 3; + } + + public static void forEachBiC(Consumer action) { + VectorUtil.iterateCuboid( + 0, + 0, + 0, + ChunkGenericRO.BLOCKS_PER_CHUNK, + ChunkGenericRO.BLOCKS_PER_CHUNK, + ChunkGenericRO.BLOCKS_PER_CHUNK, + action + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkMap.java b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkMap.java index 2fbc912..855f0d7 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkMap.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkMap.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.generic; import java.util.Collection; diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java index cd5a755..64819ae 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.generic; import java.util.Iterator; @@ -45,7 +45,7 @@ public class LongBasedChunkSet implements ChunkSet { addAll(copyFrom); } - public LongBasedChunkSet(TLongSet impl, GenericWorld copyFrom) { + public LongBasedChunkSet(TLongSet impl, WorldGenericRO copyFrom) { this(impl); addAllChunks(copyFrom.getChunks()); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericBlock.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGeneric.java similarity index 95% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericBlock.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/TileGeneric.java index d669b07..d99737f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericBlock.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGeneric.java @@ -15,10 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.generic; -public interface GenericBlock { +public interface TileGeneric { String getId(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java new file mode 100644 index 0000000..6f49630 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java @@ -0,0 +1,93 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.generic; + +/** + * A reference to a single tile in a tile stack. A {@code TileReference} remains + * valid until the tile is removed from its stack. + *

    + * Tile reference objects may be reused for other tiles; {@link #isValid()} only + * shows if there exists some tile that this object references; it may + * or may not be the tile this reference was acquired for. It is the + * responsibility of the programmer to discard references when the tile is + * removed. + */ +// @formatter:off +public interface TileGenericReferenceRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO +> { +// @formatter:on + + /** + * Gets the index that the referenced tile currently occupies. This value + * may change as tiles are added to or removed from the stack. + * + * @return the index of the tile or {@code -1} if this reference is invalid + */ + int getIndex(); + + /** + * Gets the tile stack that contains the referenced tile. + * + * @return the tile stack of the relevant tile or {@code null} if this + * reference is invalid. + */ + TS getStack(); + + /** + * Gets the tile that this object references. + * + * @return the relevant tile or {@code null} if this reference is invalid + */ + default T get() { + return getStack().get(getIndex()); + } + + /** + * Checks whether this reference is valid. A reference is valid if it points + * to some tile; it may or may not be the tile that this reference + * was acquired for. (A tile reference can only change the referenced tile + * after the previous tile is removed from the stack.) + * + * @return {@code true} iff there exists a tile that this reference points + * to. + */ + default boolean isValid() { + return get() != null; + } + + /** + * Gets the tag of the referenced tile. + * + * @return the tag or {@code -1} iff this reference is invalid. + */ + default int getTag() { + TS tileStack = getStack(); + if (tileStack == null) { + return -1; + } else { + return tileStack.getTagByIndex(getIndex()); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceWO.java new file mode 100644 index 0000000..f31eca8 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceWO.java @@ -0,0 +1,33 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.generic; + +// @formatter:off +public interface TileGenericReferenceWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO +> { +// @formatter:on + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackRO.java similarity index 66% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackRO.java index 31a5158..0a08fac 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackRO.java @@ -18,18 +18,24 @@ package ru.windcorp.progressia.common.world.generic; -import java.util.AbstractList; +import java.util.List; import java.util.Objects; import java.util.RandomAccess; import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; -public abstract class GenericTileStack, T extends GenericTile, C extends GenericChunk> - extends AbstractList - implements RandomAccess { +// @formatter:off +public interface TileGenericStackRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO +> extends List, RandomAccess { +// @formatter:on public static interface TSConsumer { void accept(int layer, T tile); @@ -37,30 +43,36 @@ public abstract class GenericTileStack public static final int TILES_PER_FACE = 8; - public abstract Vec3i getBlockInChunk(Vec3i output); + Vec3i getBlockInChunk(Vec3i output); - public abstract C getChunk(); + C getChunk(); - public abstract BlockFace getFace(); + RelFace getFace(); - public Vec3i getBlockInWorld(Vec3i output) { + TR getReference(int index); + + int getIndexByTag(int tag); + + int getTagByIndex(int index); + + default Vec3i getBlockInWorld(Vec3i output) { // This is safe return Coordinates.getInWorld(getChunk().getPosition(), getBlockInChunk(output), output); } - public boolean isFull() { + default boolean isFull() { return size() >= TILES_PER_FACE; } - public T getClosest() { + default T getClosest() { return get(0); } - public T getFarthest() { + default T getFarthest() { return get(size() - 1); } - public void forEach(TSConsumer action) { + default void forEach(TSConsumer action) { Objects.requireNonNull(action, "action"); for (int i = 0; i < size(); ++i) { action.accept(i, get(i)); @@ -68,14 +80,14 @@ public abstract class GenericTileStack } @Override - public void forEach(Consumer action) { + default void forEach(Consumer action) { Objects.requireNonNull(action, "action"); for (int i = 0; i < size(); ++i) { action.accept(get(i)); } } - public T findClosest(String id) { + default T findClosest(String id) { Objects.requireNonNull(id, "id"); for (int i = 0; i < size(); ++i) { @@ -88,7 +100,7 @@ public abstract class GenericTileStack return null; } - public T findFarthest(String id) { + default T findFarthest(String id) { Objects.requireNonNull(id, "id"); for (int i = 0; i < size(); ++i) { @@ -101,8 +113,12 @@ public abstract class GenericTileStack return null; } - public boolean contains(String id) { + default boolean contains(String id) { return findClosest(id) != null; } + default B getHost() { + return getChunk().getBlock(getBlockInChunk(null)); + } + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackWO.java similarity index 73% rename from src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackWO.java index 80f0ba4..ec5073e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackWO.java @@ -15,15 +15,22 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -package ru.windcorp.progressia.common.world.tile; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.generic.GenericTileStack; +package ru.windcorp.progressia.common.world.generic; -public abstract class TileDataStack - extends GenericTileStack { +import java.util.List; +import java.util.RandomAccess; + +// @formatter:off +public interface TileGenericStackWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO +> + extends List, RandomAccess { +// @formatter:on /** * Inserts the specified tile at the specified position in this stack. @@ -41,7 +48,7 @@ public abstract class TileDataStack * make sure to override it in subclass */ @Override - public abstract void add(int index, TileData tile); + void add(int index, T tile); /** * Adds the specified tile at the end of this stack assigning it the @@ -55,7 +62,7 @@ public abstract class TileDataStack * with the * provided tag */ - public abstract void load(TileData tile, int tag); + void load(T tile, int tag); /** * Replaces the tile at the specified position in this stack with the @@ -70,7 +77,7 @@ public abstract class TileDataStack * make sure to override it in subclass */ @Override - public abstract TileData set(int index, TileData tile); + T set(int index, T tile); /** * Removes the tile at the specified position in this list. Shifts any @@ -87,25 +94,21 @@ public abstract class TileDataStack * make sure to override it in subclass */ @Override - public abstract TileData remove(int index); - - public abstract TileReference getReference(int index); - - public abstract int getIndexByTag(int tag); - - public abstract int getTagByIndex(int index); + T remove(int index); /* * Aliases and overloads */ - public void addClosest(TileData tile) { + default void addClosest(T tile) { add(0, tile); } - public void addFarthest(TileData tile) { + default void addFarthest(T tile) { add(size(), tile); } + + boolean isFull(); /** * Attempts to {@link #add(int, TileData) add} the provided {@code tile} @@ -116,51 +119,47 @@ public abstract class TileDataStack * @param tile the tile to try to add * @return {@code true} iff this stack has changed */ - public boolean offer(int index, TileData tile) { + default boolean offer(int index, T tile) { if (isFull()) return false; add(index, tile); return true; } - public boolean offerClosest(TileData tile) { + default boolean offerClosest(T tile) { return offer(0, tile); } - public boolean offerFarthest(TileData tile) { + default boolean offerFarthest(T tile) { return offer(size(), tile); } - public TileData removeClosest() { + default T removeClosest() { return remove(0); } - public TileData removeFarthest() { + default T removeFarthest() { return remove(size() - 1); } - public TileData poll(int index) { + default T poll(int index) { if (size() <= index) return null; return remove(index); } - public TileData pollClosest() { + default T pollClosest() { return poll(0); } - public TileData pollFarthest() { + default T pollFarthest() { return poll(size() - 1); } @Override - public boolean add(TileData tile) { + default boolean add(T tile) { addFarthest(tile); return true; } - public BlockData getHost() { - return getChunk().getBlock(getBlockInChunk(null)); - } - } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java similarity index 83% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java index 943067e..f4cb845 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.generic; import java.util.Collection; @@ -26,16 +26,28 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; -public interface GenericWorld, C extends GenericChunk, E extends GenericEntity> { +// @formatter:off +public interface WorldGenericRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO , + E extends EntityGeneric +> { +// @formatter:on - Collection getChunks(); + Collection getChunks(); C getChunk(Vec3i pos); Collection getEntities(); + E getEntity(long entityId); + /* * Chunks */ @@ -47,6 +59,10 @@ public interface GenericWorld layer; + } + default boolean isChunkLoaded(Vec3i chunkPos) { return getChunk(chunkPos) != null; } - default boolean isBlockLoaded(Vec3i blockInWorld) { + default boolean isLocationLoaded(Vec3i blockInWorld) { return getChunkByBlock(blockInWorld) != null; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericWO.java new file mode 100644 index 0000000..3b9a81b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericWO.java @@ -0,0 +1,57 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.rels.BlockFace; + +//@formatter:off +public interface WorldGenericWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO , + E extends EntityGeneric +> { +//@formatter:on + + void setBlock(Vec3i blockInWorld, B block, boolean notify); + + TS getTiles(Vec3i blockInWorld, BlockFace face); + + void addEntity(E entity); + + void removeEntity(long entityId); + + default void removeEntity(E entity) { + removeEntity(entity.getEntityId()); + } + + /** + * Requests that the specified change is applied to the given entity. The + * {@code change} object provided may be stored until the change is applied. + * + * @param entity the entity to change + * @param change the change to apply + */ + void changeEntity(SE entity, StateChange change); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java new file mode 100644 index 0000000..0657a3e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java @@ -0,0 +1,102 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.StashingStack; +import ru.windcorp.progressia.common.world.generic.BlockGeneric; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.generic.TileGeneric; +import ru.windcorp.progressia.common.world.rels.RelFace; + +//@formatter:off +public abstract class AbstractContextRO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> implements TileGenericContextRO { +//@formatter:on + + public static final int MAX_SUBCONTEXTS = 64; + + protected class Frame { + + public final Vec3i location = new Vec3i(); + public RelFace face; + public int layer; + + @Override + public String toString() { + return "Frame [x=" + location.x + ", y=" + location.y + ", z=" + location.z + ", face=" + face + ", layer=" + + layer + "]"; + } + + } + + protected Frame frame = null; + + private final StashingStack frameStack = new StashingStack<>(MAX_SUBCONTEXTS, Frame::new); + + @Override + public void pop() { + if (!isSubcontexting()) { + throw new IllegalStateException("Cannot pop(): already top frame"); + } + + frameStack.pop(); + frame = frameStack.peek(); + } + + @Override + public BlockGenericContextRO push(Vec3i location) { + frame = frameStack.push(); + + frame.location.set(location.x, location.y, location.z); + frame.face = null; + frame.layer = -1; + + return this; + } + + @Override + public TileStackGenericContextRO push(Vec3i location, RelFace face) { + frame = frameStack.push(); + + frame.location.set(location.x, location.y, location.z); + frame.face = face; + frame.layer = -1; + + return this; + } + + @Override + public TileGenericContextRO push(Vec3i location, RelFace face, int layer) { + frame = frameStack.push(); + + frame.location.set(location.x, location.y, location.z); + frame.face = face; + frame.layer = layer; + + return this; + } + + public boolean isSubcontexting() { + return !frameStack.isEmpty(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java new file mode 100644 index 0000000..8984ad3 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java @@ -0,0 +1,164 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; + +/** + * A {@link Context} referencing a world with a block location specified. The + * location may or may not be loaded. + */ +//@formatter:off +public interface BlockGenericContextRO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> extends WorldContexts.Block, WorldGenericContextRO { +//@formatter:on + + /** + * Determines whether the location relevant to this context is currently + * loaded. + * + * @return {@code true} iff the location is loaded + */ + default boolean isLoaded() { + return isLocationLoaded(getLocation()); + } + + /** + * Retrieves the block at the relevant location. This method may return + * {@code null} in one of two cases: + *

      + *
    • the location that the block would occupy is not loaded, or + *
    • the corresponding chunk's terrain has not yet generated. + *
    + * + * @return the block or {@code null} if the location is not loaded + */ + default B getBlock() { + return getBlock(getLocation()); + } + + /** + * Determines whether the specified position has a tile. Block location is + * implied by the context. + * + * @param face the face of the block that the tile occupies + * @param layer the layer of the tile + * @return {@code true} iff the tile exists + */ + default boolean hasTile(RelFace face, int layer) { + return hasTile(getLocation(), face, layer); + } + + /** + * Determines whether the specified position has a tile with the given tag. + * Block location is implied by context. + * + * @param face the face of the block that the tile occupies + * @param tag the tag of the tile + * @return {@code true} iff the tile exists + */ + default boolean isTagValid(RelFace face, int tag) { + return isTagValid(getLocation(), face, tag); + } + + /** + * Retrieves the tile at the specified position. Block location is implied + * by context. This method may return {@code null} in one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the specified face, or + *
    • {@code layer} is not less than the amount of tiles in the tile stack. + *
    + * + * @param face the face of the block that the tile occupies + * @param layer the layer of the tile stack that the tile occupies + * @return the tile or {@code null} if the position does not contain a tile + */ + default T getTile(RelFace face, int layer) { + return getTile(getLocation(), face, layer); + } + + /** + * Retrieves the tile at the specified position and the tile's tag. Block + * location is implied by the context. This + * method may return {@code null} in one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the specified face, or + *
    • there is no tile with the specified tag in the tile stack. + *
    + * + * @param face the face of the block that the tile occupies + * @param tag the tag of the tile + * @return the tile or {@code null} if the position does not contain a tile + */ + default T getTileByTag(RelFace face, int tag) { + return getTileByTag(getLocation(), face, tag); + } + + /** + * Counts the amount of tiles in the specified tile stack. Block location is + * implied by the context + *

    + * This method returns {@code 0} in case the location is not loaded. + * + * @param face the face of the block that the tile stack occupies + * @return the count of tiles in the tile stack or {@code -1} if the tile + * stack could not exist + */ + default int getTileCount(RelFace face) { + return getTileCount(face); + } + + /* + * Subcontexting + */ + + @Override + default BlockGenericContextRO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockGenericContextRO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockGenericContextRO pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default TileStackGenericContextRO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileGenericContextRO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java new file mode 100644 index 0000000..3555c09 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java @@ -0,0 +1,107 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; + +/** + * A writable {@link Context} referencing a world with a block location + * specified. This context provides methods for affecting the world. The + * application of requested changes may or may not be immediate, see + * {@link #isImmediate()}. The location may or may not be loaded. + */ +//@formatter:off +public interface BlockGenericContextWO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> extends WorldContexts.Block, WorldGenericContextWO { +//@formatter:on + + /** + * Requests that a block is changed. The object provided may be stored until + * the change is applied. The location of the block is implied by the + * context. + * + * @param block the new block + * @see #isImmediate() + */ + default void setBlock(B block) { + setBlock(getLocation(), block); + } + + /** + * Requests that a tile is added to the top of the tile stack at the given + * location. The object provided may be stored until the change is applied. + * If the tile could not be added at the time of application this method + * fails silently. The location of the block is implied by the context. + * + * @param face the face of the block to add the tile to + * @param tile the tile to add + */ + default void addTile(RelFace face, T tile) { + addTile(getLocation(), face, tile); + } + + /** + * Requests that a tile identified by its tag is removed from the specified + * tile stack. If the tile could not be found at the time of application + * this method fails silently. The location of the block is implied by the + * context. + * + * @param face the of the block to remove the tile from + * @param tag the tag of the tile to remove + */ + default void removeTile(RelFace face, int tag) { + removeTile(getLocation(), face, tag); + } + + /* + * Subcontexting + */ + + @Override + default BlockGenericContextWO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockGenericContextWO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockGenericContextWO pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default TileStackGenericContextWO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileGenericContextWO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java new file mode 100644 index 0000000..1088a16 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java @@ -0,0 +1,74 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic.context; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; + +/** + * A {@link Context} referencing a world with a block location, a block face and + * a tile layer specified, effectively pointing to a single tile. The tile may + * or may not actually exist. + */ +//@formatter:off +public interface TileGenericContextRO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> extends WorldContexts.Tile, TileStackGenericContextRO { +//@formatter:on + + /** + * Determines whether the relevant position has a tile. + * + * @return {@code true} iff the tile exists + */ + default boolean hasTile() { + return hasTile(getLocation(), getFace(), getLayer()); + } + + /** + * Retrieves the tile at the relevant position. This method may return + * {@code null} in one of three cases: + *

      + *
    • the location is not loaded, + *
    • there is no tile stack on the relevant face, or + *
    • {@code layer} is not less than the amount of tiles in the tile stack. + *
    + * + * @return the tile or {@code null} if the position does not contain a tile + */ + default T getTile() { + return getTile(getLocation(), getFace(), getLayer()); + } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextRO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileGenericContextRO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java new file mode 100644 index 0000000..1193f51 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java @@ -0,0 +1,61 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic.context; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; + +/** + * A writable {@link Context} referencing a world with a block location, a block + * face and a tile layer specified, effectively pointing to a single tile. This + * context provides methods for affecting the world. The application of + * requested changes may or may not be immediate, see {@link #isImmediate()}. + * The tile may or may not actually exist. + */ +//@formatter:off +public interface TileGenericContextWO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> extends WorldContexts.Tile, TileStackGenericContextWO { +//@formatter:on + + /** + * Requests that the tile relevant to this context be removed from its tile + * stack. If the tile could not be found at the time of application this + * method fails silently. + */ + default void removeTile() { + removeTile(getLocation(), getFace(), getTag()); + } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextWO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileGenericContextWO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java new file mode 100644 index 0000000..2a5cd3c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java @@ -0,0 +1,123 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic.context; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; + +/** + * A {@link Context} referencing a world with a block location and a block face + * specified, effectively pointing to a tile stack. The tile stack may or may + * not actually exist. + */ +//@formatter:off +public interface TileStackGenericContextRO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> extends WorldContexts.TileStack, BlockGenericContextRO { +//@formatter:on + + /** + * Determines whether the specified position has a tile. Block location and + * block face are implied by the context. + * + * @param layer the layer of the tile + * @return {@code true} iff the tile exists + */ + default boolean hasTile(int layer) { + return hasTile(getLocation(), getFace(), layer); + } + + /** + * Determines whether the specified position has a tile with the given tag. + * Block location and block face are implied by the context. + * + * @param tag the tag of the tile + * @return {@code true} iff the tile exists + */ + default boolean isTagValid(int tag) { + return isTagValid(getLocation(), getFace(), tag); + } + + /** + * Retrieves the tile at the specified position. Block location and block + * face are implied by the context. This method may return {@code null} in + * one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the relevant face, or + *
    • {@code layer} is not less than the amount of tiles in the tile stack. + *
    + * + * @return the tile or {@code null} if the position does not contain a tile + */ + default T getTile(int layer) { + return getTile(getLocation(), getFace(), layer); + } + + /** + * Retrieves the tile at the specified position and the tile's tag. Block + * location and block face are implied by the context. This + * method may return {@code null} in one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the relevant face, or + *
    • there is no tile with the specified tag in the tile stack. + *
    + * + * @param tag the tag of the tile + * @return the tile or {@code null} if the position does not contain a tile + */ + default T getTileByTag(int tag) { + return getTileByTag(getLocation(), getFace(), tag); + } + + /** + * Counts the amount of tiles in the specified tile stack. Block location + * and block face are implied by the context. + *

    + * This method returns {@code 0} in case the location is not loaded. + * + * @return the count of tiles in the tile stack or {@code -1} if the tile + * stack could not exist + */ + default int getTileCount() { + return getTileCount(getLocation(), getFace()); + } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextRO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackGenericContextRO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackGenericContextRO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java new file mode 100644 index 0000000..7a618b9 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java @@ -0,0 +1,82 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic.context; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; + +/** + * A writable {@link Context} referencing a world with a block location and a + * block face specified, effectively pointing to a tile stack. This context + * provides methods for affecting the world. The application of requested + * changes may or may not be immediate, see {@link #isImmediate()}. The tile + * stack may or may not actually exist. + */ +//@formatter:off +public interface TileStackGenericContextWO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> extends WorldContexts.TileStack, BlockGenericContextWO { +//@formatter:on + + /** + * Requests that a tile is added to the top of the tile stack at the given + * location. The object provided may be stored until the change is applied. + * If the tile could not be added at the time of application this method + * fails silently. The location and the face of the block are implied by the + * context. + * + * @param tile the tile to add + */ + default void addTile(T tile) { + addTile(getLocation(), getFace(), tile); + } + + /** + * Requests that a tile identified by its tag is removed from the specified + * tile stack. If the tile could not be found at the time of application + * this method fails silently. The location and the face of the block are + * implied by the context. + * + * @param tag the tag of the tile to remove + */ + default void removeTile(int tag) { + removeTile(getLocation(), getFace(), tag); + } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextWO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackGenericContextWO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackGenericContextWO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java new file mode 100644 index 0000000..f8953d3 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java @@ -0,0 +1,368 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.generic.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; + +/** + * This class defines several {@link Context} subinterfaces that are further + * extended by Generic contexts. These interfaces declare methods for + * determining which location is "relevant" to the context and the basic + * subcontexting methods. Since they are not Java generics they can safely be + * extended more than once. + *

    + * Do not reuse these interfaces outside the Generic contexts' package; consider + * them to be an implementation detail. + * + * @author javapony + */ +class WorldContexts { + + /** + * A {@link Context} with a world instance. This interface should not be + * implemented directly; see {@link WorldGenericContextRO} or + * {@link WorldGenericContextWO}. + * + * @author javapony + */ + public static interface World extends Context { + + /** + * Assigns the specified location to this context. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param location the new location to use + * @return this object + * @see #pop() + */ + Block push(Vec3i location); + + /** + * Assigns the specified location and block face to this context. Tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param location the new location to use + * @param face the new block face to use + * @return this object + * @see #pop() + */ + TileStack push(Vec3i location, RelFace face); + + /** + * Assigns the specified position to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param location the new location to use + * @param face the new block face to use + * @param layer the new tile layer to use + * @return this object + * @see #pop() + */ + Tile push(Vec3i location, RelFace face, int layer); + + /** + * Converts the provided location given in the context's coordinate + * space to the underlying absolute coordinate space. + *

    + * The definition of "absolute coordinate space" for contexts that are + * not {@linkplain #isReal() real} may be arbitrary, but methods + * {@link #toAbsolute(Vec3i, Vec3i)}, {@link #toAbsolute(BlockFace)}, + * {@link #toContext(Vec3i, Vec3i)} and {@link #toContext(AbsFace)} are + * guaranteed to be consistent for all contexts. + * + * @param contextLocation the location expressed in context coordinate + * system + * @param output the {@link Vec3i} object to output the result + * into, or {@code null} + * @return The location expressed in absolute coordinate system. If + * {@code output} is not {@code null}, {@code output} is + * returned; otherwise, a new {@link Vec3i} is instantiated and + * returned + */ + Vec3i toAbsolute(Vec3i contextLocation, Vec3i output); + + /** + * Converts the provided location given in the absolute coordinate + * space to the context coordinate space. + *

    + * The definition of "absolute coordinate space" for contexts that are + * not {@linkplain #isReal() real} may be arbitrary, but methods + * {@link #toAbsolute(Vec3i, Vec3i)}, {@link #toAbsolute(BlockFace)}, + * {@link #toContext(Vec3i, Vec3i)} and {@link #toContext(AbsFace)} are + * guaranteed to be consistent for all contexts. + * + * @param contextLocation the location expressed in absolute coordinate + * system + * @param output the {@link Vec3i} object to output the result + * into, or {@code null} + * @return The location expressed in context coordinate system. If + * {@code output} is not {@code null}, {@code output} is + * returned; otherwise, a new {@link Vec3i} is instantiated and + * returned + */ + Vec3i toContext(Vec3i absoluteLocation, Vec3i output); + + /** + * Converts the provided face given in the context's coordinate + * space to the underlying absolute coordinate space. + *

    + * The definition of "absolute coordinate space" for contexts that are + * not {@linkplain #isReal() real} may be arbitrary, but methods + * {@link #toAbsolute(Vec3i, Vec3i)}, {@link #toAbsolute(BlockFace)}, + * {@link #toContext(Vec3i, Vec3i)} and {@link #toContext(AbsFace)} are + * guaranteed to be consistent for all contexts. + * + * @param contextLocation the face expressed in context coordinate + * system + * @return the face expressed in absolute coordinate system + */ + AbsFace toAbsolute(RelFace contextFace); + + /** + * Converts the provided face given in the absolute coordinate + * space to the context coordinate space. + *

    + * The definition of "absolute coordinate space" for contexts that are + * not {@linkplain #isReal() real} may be arbitrary, but methods + * {@link #toAbsolute(Vec3i, Vec3i)}, {@link #toAbsolute(BlockFace)}, + * {@link #toContext(Vec3i, Vec3i)} and {@link #toContext(AbsFace)} are + * guaranteed to be consistent for all contexts. + * + * @param contextLocation the face expressed in absolute coordinate + * system + * @return the face expressed in context coordinate system + */ + RelFace toContext(AbsFace absoluteFace); + + } + + /** + * A {@link Context} with a world instance and a block location. This + * interface + * should not be implemented directly; see {@link BlockGenericContextRO} or + * {@link BlockGenericContextWO}. + * + * @author javapony + */ + public static interface Block extends World { + + /** + * Returns the location of the block. + *

    + * The coordinate system in use is not specified, but it is consistent + * across + * all methods of this context. + *

    + * The object returned by this method must not be modified. It is only + * valid + * while the context is {@linkplain valid}. + * + * @return a vector describing the block's position + */ + Vec3i getLocation(); + + /** + * Shifts the location in the specified direction. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param dx the change of the x component + * @param dy the change of the y component + * @param dz the change of the z component + * @return this object + * @see #pop() + */ + default Block pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + /** + * Shifts the location in the specified direction. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param direction the change added to the current location + * @return this object + * @see #pop() + */ + default Block pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + /** + * Shifts the location in the specified direction. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param direction the change added to the current location + * @return this object + * @see #pop() + */ + default Block pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + /** + * Assigns the specified block face to this context. Tile layer + * information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param face the new block face to use + * @return this object + * @see #pop() + */ + default TileStack push(RelFace face) { + return push(getLocation(), face); + } + + /** + * Assigns the specified block face and tile layer to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param face the new block face to use + * @param layer the new tile layer to use + * @return this object + * @see #pop() + */ + default Tile push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + + } + + /** + * A {@link Context} with a world instance, a block location and a block + * face + * (block side). This interface should not be implemented directly; see + * {@link TileStackGenericContextRO} or {@link TileStackGenericContextWO}. + * + * @author javapony + */ + public static interface TileStack extends Block { + + /** + * Returns the face relevant to this context. + * + * @return the block face + */ + RelFace getFace(); + + /** + * Assigns the specified tile layer to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param layer the new tile layer to use + * @return this object + * @see #pop() + */ + default Tile push(int layer) { + return push(getLocation(), getFace(), layer); + } + + /** + * Assigns the counter face (the face on the opposite side of this + * block) to this context. Tile layer information is discarded if it was + * present. See {@linkplain Context#subcontexting subcontexting} for + * more details. + * + * @return this object + * @see #pop() + */ + default TileStack pushCounter() { + return push(getFace().getCounter()); + } + + /** + * Assigns the face opposite to the current face to this context. The + * current face and its opposite are the only two tile stacks occupying + * the gap between the two respective blocks. Tile layer information is + * discarded if it was present. See {@linkplain Context#subcontexting + * subcontexting} for + * more details. + * + * @return this object + * @see #pop() + */ + default TileStack pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + + } + + /** + * A {@link Context} with a world instance, a block location, a block face + * (block side) and a tile layer. This interface should not be implemented + * directly; see {@link TileGenericContextRO} or + * {@link TileGenericContextWO}. + * + * @author javapony + */ + public static interface Tile extends TileStack { + + /** + * Returns the tile layer relevant to this context. + * + * @return the tile layer + */ + int getLayer(); + + /** + * Gets the tag of the tile at the relevant position. + * + * @return the tag of the tile or {@code -1} if the location is not + * loaded + * or the tile does not exist + */ + int getTag(); + + /** + * Assigns the tile layer closer to the host block to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @return this object + * @see #pop() + */ + default Tile pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + /** + * Assigns the tile layer farther to the host block to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @return this object + * @see #pop() + */ + default Tile pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + + } + + WorldContexts() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java new file mode 100644 index 0000000..ec188d1 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java @@ -0,0 +1,157 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic.context; + +import java.util.Collection; +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.RelFace; + +/** + * A {@link Context} with a world instance. + *

    + * This interfaces defines the entirety of world query methods supported by the + * default contexts. + */ +// @formatter:off +public interface WorldGenericContextRO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> extends WorldContexts.World { +// @formatter:on + + /** + * Retrieves the block at the specified location. This method may return + * {@code null} in one of two cases: + *

      + *
    • the location that the block would occupy is not loaded, or + *
    • the corresponding chunk's terrain has not yet generated. + *
    + * + * @param location the location to query + * @return the block or {@code null} if the location is not loaded + */ + B getBlock(Vec3i location); + + /** + * Determines whether the specified location is loaded. + * + * @param location the location to query + * @return {@code true} iff the location is loaded + */ + boolean isLocationLoaded(Vec3i location); + + /** + * Retrieves the tile at the specified position. This method may return + * {@code null} in one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the specified face, or + *
    • {@code layer} is not less than the amount of tiles in the tile stack. + *
    + * + * @param location location of the host block + * @param face the face of the block that the tile occupies + * @param layer the layer of the tile stack that the tile occupies + * @return the tile or {@code null} if the position does not contain a tile + */ + T getTile(Vec3i location, RelFace face, int layer); + + /** + * Retrieves the tile at the specified position and the tile's tag. This + * method may return {@code null} in one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the specified face, or + *
    • there is no tile with the specified tag in the tile stack. + *
    + * + * @param location location of the host block + * @param face the face of the block that the tile occupies + * @param tag the tag of the tile + * @return the tile or {@code null} if the position does not contain a tile + */ + T getTileByTag(Vec3i location, RelFace face, int tag); + + /** + * Determines whether the specified position has a tile. + * + * @param location location of the host block + * @param face the face of the block that the tile occupies + * @param layer the layer of the tile + * @return {@code true} iff the tile exists + */ + boolean hasTile(Vec3i location, RelFace face, int layer); + + /** + * Determines whether the specified position has a tile with the given tag. + * + * @param location location of the host block + * @param face the face of the block that the tile occupies + * @param tag the tag of the tile + * @return {@code true} iff the tile exists + */ + boolean isTagValid(Vec3i location, RelFace face, int tag); + + /** + * Counts the amount of tiles in the specified tile stack. + *

    + * This method returns {@code 0} in case the location is not loaded. + * + * @param location location of the host block + * @param face the face of the block that the tile stack occupies + * @return the count of tiles in the tile stack or {@code -1} if the tile + * stack could not exist + */ + int getTileCount(Vec3i location, RelFace face); + + /** + * Retrieves a listing of all entities. {@link #forEachEntity(Consumer)} + * should be used to iterate the collection. The collection is not + * modifiable. + * + * @return all loaded entities + */ + Collection getEntities(); + + /** + * Retrieves the entity with the specified entity ID. + * + * @param entityId the entity ID to look up + * @return the entity found or {@code null} + */ + E getEntity(long entityId); + + /* + * Subcontexting + */ + + @Override + BlockGenericContextRO push(Vec3i location); + + @Override + TileStackGenericContextRO push(Vec3i location, RelFace face); + + @Override + TileGenericContextRO push(Vec3i location, RelFace face, int layer); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java new file mode 100644 index 0000000..d1dac01 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java @@ -0,0 +1,164 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.RelFace; + +/** + * A writable {@link Context} with a world instance. This context provides + * methods for affecting the world. The application of requested changes may or + * may not be immediate, see {@link #isImmediate()}. + *

    + * This interfaces defines the entirety of world modification methods supported + * by the default contexts. + */ +// @formatter:off +public interface WorldGenericContextWO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> extends WorldContexts.World { +// @formatter:on + + /** + * Queries whether changes requested with this context are guaranteed to be + * applied immediately. + *

    + * When the changes are applied immediately, all subsequent queries will + * reflect the change. When the changes are not applied immediately, none of + * the subsequent queries will be affected by the requests while the context + * is {@linkplain Context#validity valid}. Immediate mode does not change + * while the context is valid. + * + * @return {@code true} iff changes are visible immediately + */ + boolean isImmediate(); + + /** + * Requests that a block is changed. The object provided may be stored until + * the change is applied. + * + * @param location the location of the change + * @param block the new block + * @see #isImmediate() + */ + void setBlock(Vec3i location, B block); + + /** + * Requests that a tile is added to the top of the tile stack at the given + * location. The object provided may be stored until the change is applied. + * If the tile could not be added at the time of application this method + * fails silently. + * + * @param location the location of the block to which the tile is to be + * added + * @param face the face of the block to add the tile to + * @param tile the tile to add + */ + void addTile(Vec3i location, RelFace face, T tile); + + /** + * Requests that a tile identified by its tag is removed from the specified + * tile stack. If the tile could not be found at the time of application + * this method fails silently. + * + * @param location the location of the block from which the tile is to be + * removed + * @param face the of the block to remove the tile from + * @param tag the tag of the tile to remove + */ + void removeTile(Vec3i location, RelFace face, int tag); + + /** + * Requests that the referenced tile is removed from its tile stack. If the + * tile could not be found at the time of application this method fails + * silently. + * + * @param tileReference a reference to the tile + */ + default void removeTile(TileGenericReferenceRO tileReference) { + TileGenericStackRO tileStack = tileReference.getStack(); + + if (tileStack == null) { + return; + } + + removeTile(tileStack.getBlockInWorld(null), tileStack.getFace(), tileReference.getTag()); + } + + /** + * Requests that an entity is added to the world. The object provided may be + * stored until the change is applied. If the entity was already added to + * the world at the time of application this method does nothing. + * + * @param entity the entity to add + * @see #isImmediate() + */ + void addEntity(E entity); + + /** + * Requests that an entity with the given entity ID is removed from the + * world. If the entity did not exist at the time of application this method + * fails silently. + * + * @param entityId the ID of the entity to remove + * @see #isImmediate() + * @see #removeEntity(EntityGeneric) + */ + void removeEntity(long entityId); + + /** + * Requests that the entity is removed from the world. If the entity did not + * exist at the time of application this method fails silently. + * + * @param entity the entity to remove + * @see #isImmediate() + * @see #removeEntity(long) + */ + default void removeEntity(E entity) { + removeEntity(entity.getEntityId()); + } + + /** + * Requests that the specified change is applied to the given entity. The + * {@code change} object provided may be stored until the change is applied. + * + * @param entity the entity to change + * @param change the change to apply + */ + void changeEntity(SE entity, StateChange change); + + /* + * Subcontexting + */ + + @Override + BlockGenericContextWO push(Vec3i location); + + @Override + TileStackGenericContextWO push(Vec3i location, RelFace face); + + @Override + TileGenericContextWO push(Vec3i location, RelFace face, int layer); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java index 7c2a35c..df47640 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java @@ -25,9 +25,9 @@ import java.io.IOException; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public abstract class ChunkCodec extends Namespaced { @@ -46,12 +46,12 @@ public abstract class ChunkCodec extends Namespaced { return signature; } - public abstract ChunkData decode(WorldData world, Vec3i position, DataInputStream input, IOContext context) + public abstract DefaultChunkData decode(DefaultWorldData world, Vec3i position, DataInputStream input, IOContext context) throws DecodingException, IOException; - public abstract boolean shouldEncode(ChunkData chunk, IOContext context); + public abstract boolean shouldEncode(DefaultChunkData chunk, IOContext context); - public abstract void encode(ChunkData chunk, DataOutputStream output, IOContext context) throws IOException; + public abstract void encode(DefaultChunkData chunk, DataOutputStream output, IOContext context) throws IOException; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java index 025738f..b2a1cd2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java @@ -31,16 +31,16 @@ import gnu.trove.map.TByteObjectMap; import gnu.trove.map.hash.TByteObjectHashMap; import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class ChunkIO { private static final TByteObjectMap CODECS_BY_ID = new TByteObjectHashMap<>(); private static final List CODECS_BY_PRIORITY = new ArrayList<>(); - public static ChunkData load(WorldData world, Vec3i position, DataInputStream data, IOContext context) + public static DefaultChunkData load(DefaultWorldData world, Vec3i position, DataInputStream data, IOContext context) throws DecodingException, IOException { if (CODECS_BY_ID.isEmpty()) @@ -73,7 +73,7 @@ public class ChunkIO { } } - public static void save(ChunkData chunk, DataOutputStream output, IOContext context) + public static void save(DefaultChunkData chunk, DataOutputStream output, IOContext context) throws IOException { ChunkCodec codec = getCodec(chunk, context); @@ -100,7 +100,7 @@ public class ChunkIO { return CODECS_BY_ID.get(signature); } - public static ChunkCodec getCodec(ChunkData chunk, IOContext context) { + public static ChunkCodec getCodec(DefaultChunkData chunk, IOContext context) { for (ChunkCodec codec : CODECS_BY_PRIORITY) { if (codec.shouldEncode(chunk, context)) { return codec; diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java new file mode 100644 index 0000000..d741bac --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java @@ -0,0 +1,322 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.rels; + +import java.util.Objects; +import java.util.function.Function; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; + +public final class AbsFace extends AbsRelation implements BlockFace { + + // @formatter:off + public static final AbsFace + POS_Z = new AbsFace( 0, 0, +1, true, "POS_Z"), + NEG_Z = new AbsFace( 0, 0, -1, false, "NEG_Z"), + POS_X = new AbsFace(+1, 0, 0, true, "POS_X"), + NEG_X = new AbsFace(-1, 0, 0, false, "NEG_X"), + POS_Y = new AbsFace( 0, +1, 0, false, "POS_Y"), + NEG_Y = new AbsFace( 0, -1, 0, true, "NEG_Y"); + // @formatter:on + + private static final ImmutableList ALL_FACES = ImmutableList.of(POS_Z, NEG_Z, POS_X, NEG_X, POS_Y, NEG_Y); + + static { + link(POS_Z, NEG_Z); + link(POS_X, NEG_X); + link(POS_Y, NEG_Y); + } + + private static final ImmutableList PRIMARY_FACES = ALL_FACES.stream().filter(AbsFace::isPrimary) + .collect(ImmutableList.toImmutableList()); + + private static final ImmutableList SECONDARY_FACES = ALL_FACES.stream().filter(AbsFace::isSecondary) + .collect(ImmutableList.toImmutableList()); + + public static final int PRIMARY_BLOCK_FACE_COUNT = PRIMARY_FACES.size(); + public static final int SECONDARY_BLOCK_FACE_COUNT = SECONDARY_FACES.size(); + + public static ImmutableList getFaces() { + return ALL_FACES; + } + + public static ImmutableList getPrimaryFaces() { + return PRIMARY_FACES; + } + + public static ImmutableList getSecondaryFaces() { + return SECONDARY_FACES; + } + + private static void link(AbsFace a, AbsFace b) { + a.counterFace = b; + b.counterFace = a; + } + + public static ImmutableMap mapToFaces( + E posZ, + E negZ, + E posX, + E negX, + E negY, + E posY + ) { + return ImmutableMap.builderWithExpectedSize(6) + .put(POS_Z, posZ) + .put(NEG_Z, negZ) + .put(POS_X, posX) + .put(NEG_X, negX) + .put(NEG_Y, negY) + .put(POS_Y, posY) + .build(); + } + + public static ImmutableMap mapToFaces(Function generator) { + return mapToFaces( + generator.apply(POS_Z), + generator.apply(NEG_Z), + generator.apply(POS_X), + generator.apply(NEG_X), + generator.apply(NEG_Y), + generator.apply(POS_Y) + ); + } + + /** + * Rounds the provided vector to one of {@link AbsFace}s. The returned face + * is pointing in the same general direction as the provided vector. The + * result is undefined for arguments where two largest in absolute values + * coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector + * the result is {@code null}. Infinite vectors are handled correctly. + * + * @param vector the vector to round + * @return the face most adequately describing the provided vector, or + * {@code null} iff {@code vector.x = vector.y = vector.z = 0} + * @throws IllegalArgumentException if one of the coordinates is a NaN + */ + public static AbsFace roundToFace(Vec3 vector) { + Objects.requireNonNull(vector, "vector"); + return roundToFace(vector.x, vector.y, vector.z); + } + + /** + * Rounds the provided vector to one of {@link AbsFace}s. The returned face + * is pointing in the same general direction as the provided vector. The + * result is undefined for arguments where two largest in absolute values + * coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector + * the result is {@code null}. Infinite arguments are handled correctly. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + * @return the face most adequately describing the provided vector, or + * {@code null} iff {@code x = y = z = 0} + * @throws IllegalArgumentException if one of the coordinates is a NaN + */ + public static AbsFace roundToFace(float x, float y, float z) { + if (x == 0 && y == 0 && z == 0) { + return null; + } + + if (Float.isNaN(x) || Float.isNaN(y) || Float.isNaN(z)) { + throw new IllegalArgumentException("Vector contains NaN: (" + x + "; " + y + "; " + z + ")"); + } + + // The following code handles infinite x, y or z properly + + float absX = Math.abs(x); + float absY = Math.abs(y); + float absZ = Math.abs(z); + + if (absX > absY) { + if (absX > absZ) { + return x > 0 ? POS_X : NEG_X; + } else { + // Z is the answer; exit decision tree + } + } else { + if (absY > absZ) { + return y > 0 ? POS_Y : NEG_Y; + } else { + // Z is the answer; exit decision tree + } + } + + return z > 0 ? POS_Z : NEG_Z; + } + + /** + * Rounds the provided vector to one of {@link AbsFace}s. The returned face + * is pointing in the same general direction as the provided vector. The + * result is undefined for arguments where two largest in absolute values + * coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector + * the result is {@code null}. + * + * @param vector the vector to round + * @return the face most adequately describing the provided vector, or + * {@code null} iff {@code vector.x = vector.y = vector.z = 0} + */ + public static AbsFace roundToFace(Vec3i vector) { + Objects.requireNonNull(vector, "vector"); + return roundToFace(vector.x, vector.y, vector.z); + } + + /** + * Rounds the provided vector to one of {@link AbsFace}s. The returned face + * is pointing in the same general direction as the provided vector. The + * result is undefined for arguments where two largest in absolute values + * coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector + * the result is {@code null}. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + * @return the face most adequately describing the provided vector, or + * {@code null} iff {@code x = y = z = 0} + */ + public static AbsFace roundToFace(int x, int y, int z) { + if (x == 0 && y == 0 && z == 0) { + return null; + } + + int absX = Math.abs(x); + int absY = Math.abs(y); + int absZ = Math.abs(z); + + if (absX > absY) { + if (absX > absZ) { + return x > 0 ? POS_X : NEG_X; + } else { + // Z is the answer; exit decision tree + } + } else { + if (absY > absZ) { + return y > 0 ? POS_Y : NEG_Y; + } else { + // Z is the answer; exit decision tree + } + } + + return z > 0 ? POS_Z : NEG_Z; + } + + private static int nextId = 0; + + private final int id; + private final String name; + private AbsFace counterFace; + private final boolean isPrimary; + + private AbsFace(int x, int y, int z, boolean isPrimary, String name) { + super(x, y, z); + this.id = nextId++; + this.isPrimary = isPrimary; + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public AbsFace resolve(AbsFace up) { + return this; + } + + @Override + public RelFace relativize(AbsFace up) { + return BlockFaceResolver.relativize(this, up); + } + + public boolean isPrimary() { + return isPrimary; + } + + public AbsFace getPrimary() { + if (isPrimary) + return this; + else + return counterFace; + } + + public AbsFace getPrimaryAndMoveCursor(Vec3i cursor) { + if (isPrimary) + return this; + + cursor.add(getVector()); + return counterFace; + } + + public boolean isSecondary() { + return !isPrimary; + } + + public AbsFace getSecondary() { + if (isPrimary) + return counterFace; + else + return this; + } + + public AbsFace getSecondaryAndMoveCursor(Vec3i cursor) { + if (!isPrimary) + return this; + + cursor.add(getVector()); + return counterFace; + } + + public AbsFace getCounter() { + return counterFace; + } + + public AbsFace getCounterAndMoveCursor(Vec3i cursor) { + cursor.add(getVector()); + return counterFace; + } + + public int getId() { + return id; + } + + @Override + public float getEuclideanDistance() { + return 1.0f; + } + + @Override + public int getChebyshevDistance() { + return 1; + } + + @Override + public int getManhattanDistance() { + return 1; + } + + @Override + public String toString() { + return getName(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java new file mode 100644 index 0000000..b14abdd --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java @@ -0,0 +1,88 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.rels; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; + +public class AbsRelation extends BlockRelation { + + private final Vec3i vector = new Vec3i(); + private final Vec3 floatVector = new Vec3(); + private final Vec3 normalized = new Vec3(); + + public AbsRelation(int x, int y, int z) { + vector.set(x, y, z); + floatVector.set(x, y, z); + normalized.set(x, y, z); + + if (x != 0 || y != 0 || z != 0) { + normalized.normalize(); + } + } + + public AbsRelation(Vec3i vector) { + this(vector.x, vector.y, vector.z); + } + + public static AbsRelation of(Vec3i vector) { + return of(vector.x, vector.y, vector.z); + } + + public static AbsRelation of(int x, int y, int z) { + if (Math.abs(x) + Math.abs(y) + Math.abs(z) == 1) { + return AbsFace.roundToFace(x, y, z); + } + + return new AbsRelation(x, y, z); + } + + @Override + public AbsRelation resolve(AbsFace up) { + return this; + } + + @Override + public Vec3i getVector(AbsFace up) { + return vector; + } + + @Override + public Vec3 getFloatVector(AbsFace up) { + return floatVector; + } + + @Override + public Vec3 getNormalized(AbsFace up) { + return normalized; + } + + public Vec3i getVector() { + return vector; + } + + public Vec3 getFloatVector() { + return floatVector; + } + + public Vec3 getNormalized() { + return normalized; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/AxisRotations.java b/src/main/java/ru/windcorp/progressia/common/world/rels/AxisRotations.java new file mode 100644 index 0000000..2d13c19 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/AxisRotations.java @@ -0,0 +1,193 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.rels; + +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.NEG_X; +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.NEG_Y; +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.NEG_Z; +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.POS_X; +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.POS_Y; +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.POS_Z; + +import java.util.Map; + +import glm.mat._3.Mat3; +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.util.VectorUtil.SignedAxis; + +public class AxisRotations { + + private static class Rotation { + private static class MyMat3i { + private final int m00, m01, m02, m10, m11, m12, m20, m21, m22; + + public MyMat3i(Mat3 integerMatrix) { + this.m00 = (int) integerMatrix.m00; + this.m01 = (int) integerMatrix.m01; + this.m02 = (int) integerMatrix.m02; + this.m10 = (int) integerMatrix.m10; + this.m11 = (int) integerMatrix.m11; + this.m12 = (int) integerMatrix.m12; + this.m20 = (int) integerMatrix.m20; + this.m21 = (int) integerMatrix.m21; + this.m22 = (int) integerMatrix.m22; + } + + public Vec3i mul(Vec3i right, Vec3i res) { + res.set( + m00 * right.x + m10 * right.y + m20 * right.z, + m01 * right.x + m11 * right.y + m21 * right.z, + m02 * right.x + m12 * right.y + m22 * right.z + ); + return res; + } + } + + private final Mat3 resolutionMatrix3 = new Mat3(); + private final Mat4 resolutionMatrix4 = new Mat4(); + private final MyMat3i resolutionMatrix3i; + + private final Mat3 relativizationMatrix3 = new Mat3(); + private final Mat4 relativizationMatrix4 = new Mat4(); + private final MyMat3i relativizationMatrix3i; + + private Rotation(SignedAxis northDestination, SignedAxis westDestination, SignedAxis upDestination) { + resolutionMatrix3.c0(computeUnitVectorAlong(northDestination)); + resolutionMatrix3.c1(computeUnitVectorAlong(westDestination)); + resolutionMatrix3.c2(computeUnitVectorAlong(upDestination)); + + resolutionMatrix3.toMat4(resolutionMatrix4); + resolutionMatrix3i = new MyMat3i(resolutionMatrix3); + + relativizationMatrix3.set(resolutionMatrix3).transpose(); + relativizationMatrix4.set(resolutionMatrix4).transpose(); + relativizationMatrix3i = new MyMat3i(relativizationMatrix3); + } + + private static Vec3 computeUnitVectorAlong(SignedAxis signedAxis) { + Vec3 result = new Vec3(0, 0, 0); + VectorUtil.set(result, signedAxis.getAxis(), signedAxis.getSign()); + return result; + } + + /** + * @return the resolutionMatrix3 + */ + public Mat3 getResolutionMatrix3() { + return resolutionMatrix3; + } + + /** + * @return the resolutionMatrix4 + */ + public Mat4 getResolutionMatrix4() { + return resolutionMatrix4; + } + + /** + * @return the relativizationMatrix3 + */ + public Mat3 getRelativizationMatrix3() { + return relativizationMatrix3; + } + + /** + * @return the relativizationMatrix4 + */ + public Mat4 getRelativizationMatrix4() { + return relativizationMatrix4; + } + + public Vec3i resolve(Vec3i output, Vec3i input) { + if (output == null) { + output = new Vec3i(); + } + resolutionMatrix3i.mul(input, output); + return output; + } + + public Vec3i relativize(Vec3i output, Vec3i input) { + if (output == null) { + output = new Vec3i(); + } + relativizationMatrix3i.mul(input, output); + return output; + } + + public Vec3 resolve(Vec3 output, Vec3 input) { + if (output == null) { + output = new Vec3(); + } + resolutionMatrix3.mul(input, output); + return output; + } + + public Vec3 relativize(Vec3 output, Vec3 input) { + if (output == null) { + output = new Vec3(); + } + relativizationMatrix3.mul(input, output); + return output; + } + } + + private final static Map TRANSFORMATIONS = AbsFace.mapToFaces( + new Rotation(POS_X, POS_Y, POS_Z), + new Rotation(POS_X, NEG_Y, NEG_Z), + new Rotation(POS_Z, NEG_Y, POS_X), + new Rotation(POS_Z, POS_Y, NEG_X), + new Rotation(POS_Z, NEG_X, NEG_Y), + new Rotation(POS_Z, POS_X, POS_Y) + ); + + public static Vec3i resolve(Vec3i relative, AbsFace up, Vec3i output) { + return TRANSFORMATIONS.get(up).resolve(output, relative); + } + + public static Vec3 resolve(Vec3 relative, AbsFace up, Vec3 output) { + return TRANSFORMATIONS.get(up).resolve(output, relative); + } + + public static Vec3i relativize(Vec3i absolute, AbsFace up, Vec3i output) { + return TRANSFORMATIONS.get(up).relativize(output, absolute); + } + + public static Vec3 relativize(Vec3 absolute, AbsFace up, Vec3 output) { + return TRANSFORMATIONS.get(up).relativize(output, absolute); + } + + public static Mat3 getResolutionMatrix3(AbsFace up) { + return TRANSFORMATIONS.get(up).getResolutionMatrix3(); + } + + public static Mat4 getResolutionMatrix4(AbsFace up) { + return TRANSFORMATIONS.get(up).getResolutionMatrix4(); + } + + public static Mat3 getRelativizationMatrix3(AbsFace up) { + return TRANSFORMATIONS.get(up).getRelativizationMatrix3(); + } + + public static Mat4 getRelativizationMatrix4(AbsFace up) { + return TRANSFORMATIONS.get(up).getRelativizationMatrix4(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFace.java b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFace.java new file mode 100644 index 0000000..bdbccaf --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFace.java @@ -0,0 +1,42 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.rels; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; + +public interface BlockFace { + + public static final int BLOCK_FACE_COUNT = 6; + + AbsFace resolve(AbsFace up); + RelFace relativize(AbsFace up); + + public default Vec3i getVector(AbsFace up) { + return resolve(up).getVector(); + } + + public default Vec3 getFloatVector(AbsFace up) { + return resolve(up).getFloatVector(); + } + + public default Vec3 getNormalized(AbsFace up) { + return resolve(up).getNormalized(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java new file mode 100644 index 0000000..e1f469e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java @@ -0,0 +1,78 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.rels; + +import java.util.Objects; + +import static ru.windcorp.progressia.common.world.rels.AbsFace.BLOCK_FACE_COUNT; + +public class BlockFaceResolver { + + /** + * A mapping from (up; relative) to absolute. Face IDs are used as keys. + */ + private static final AbsFace[][] RESOLUTION_TABLE = new AbsFace[BLOCK_FACE_COUNT][BLOCK_FACE_COUNT]; + + /** + * A mapping from (up; absolute) to relative. Face IDs are used as keys. + */ + private static final RelFace[][] RELATIVIZATION_TABLE = new RelFace[BLOCK_FACE_COUNT][BLOCK_FACE_COUNT]; + + static { + for (AbsFace up : AbsFace.getFaces()) { + for (RelFace relative : RelFace.getFaces()) { + + AbsFace absolute = (AbsFace) AbsRelation.of(AxisRotations.resolve(relative.getRelVector(), up, null)); + + RESOLUTION_TABLE[up.getId()][relative.getId()] = absolute; + RELATIVIZATION_TABLE[up.getId()][absolute.getId()] = relative; + + } + } + } + + public static AbsFace resolve(RelFace relative, AbsFace up) { + Objects.requireNonNull(relative, "relative"); + Objects.requireNonNull(up, "up"); + + if (relative == RelFace.UP) { + return up; + } else if (relative == RelFace.DOWN) { + return up.getCounter(); + } + + return RESOLUTION_TABLE[up.getId()][relative.getId()]; + } + + public static RelFace relativize(AbsFace absolute, AbsFace up) { + Objects.requireNonNull(absolute, "absolute"); + Objects.requireNonNull(up, "up"); + + if (absolute == up) { + return RelFace.UP; + } else if (absolute.getCounter() == up) { + return RelFace.DOWN; + } + + return RELATIVIZATION_TABLE[up.getId()][absolute.getId()]; + } + + private BlockFaceResolver() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockRelation.java b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockRelation.java similarity index 76% rename from src/main/java/ru/windcorp/progressia/common/world/block/BlockRelation.java rename to src/main/java/ru/windcorp/progressia/common/world/rels/BlockRelation.java index 659a5fa..f235fc4 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockRelation.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockRelation.java @@ -15,8 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -package ru.windcorp.progressia.common.world.block; +package ru.windcorp.progressia.common.world.rels; import static java.lang.Math.abs; import static java.lang.Math.max; @@ -24,34 +23,26 @@ import static java.lang.Math.max; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; -public class BlockRelation { +public abstract class BlockRelation { - private final Vec3i vector = new Vec3i(); - private final Vec3 floatVector = new Vec3(); - private final Vec3 normalized = new Vec3(); - - public BlockRelation(int x, int y, int z) { - vector.set(x, y, z); - floatVector.set(x, y, z); - normalized.set(x, y, z).normalize(); - } - - public BlockRelation(Vec3i vector) { - this(vector.x, vector.y, vector.z); - } - - public Vec3i getVector() { - return vector; + public abstract AbsRelation resolve(AbsFace up); + + public Vec3i getVector(AbsFace up) { + return resolve(up).getVector(); } - public Vec3 getFloatVector() { - return floatVector; + public Vec3 getFloatVector(AbsFace up) { + return resolve(up).getFloatVector(); } - - public Vec3 getNormalized() { - return normalized; + + public Vec3 getNormalized(AbsFace up) { + return resolve(up).getNormalized(); } - + + protected Vec3i getSample() { + return getVector(AbsFace.POS_Z); + } + /** * Returns the distance between the source and destination blocks, as * defined by the Euclidean space. Your everyday distance. @@ -59,7 +50,7 @@ public class BlockRelation { * @return square root of the sum of the squares of the coordinates */ public float getEuclideanDistance() { - return vector.length(); + return getSample().length(); } /** @@ -72,6 +63,7 @@ public class BlockRelation { * @return the sum of the absolute values of the coordinates */ public int getManhattanDistance() { + Vec3i vector = getSample(); return abs(vector.x) + abs(vector.y) + abs(vector.z); } @@ -83,7 +75,8 @@ public class BlockRelation { * @return the maximum of the absolute values of the coordinates */ public int getChebyshevDistance() { + Vec3i vector = getSample(); return max(abs(vector.x), max(abs(vector.y), abs(vector.z))); } - + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java b/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java new file mode 100644 index 0000000..99e97fb --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java @@ -0,0 +1,155 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.rels; + +import java.util.function.Function; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import glm.vec._3.i.Vec3i; + +public class RelFace extends RelRelation implements BlockFace { + + // @formatter:off + public static final RelFace + UP = new RelFace( 0, 0, +1, "UP"), + DOWN = new RelFace( 0, 0, -1, "DOWN"), + NORTH = new RelFace(+1, 0, 0, "NORTH"), + SOUTH = new RelFace(-1, 0, 0, "SOUTH"), + WEST = new RelFace( 0, +1, 0, "WEST"), + EAST = new RelFace( 0, -1, 0, "EAST"); + // @formatter:on + + private static final ImmutableList ALL_FACES = ImmutableList.of(UP, DOWN, NORTH, SOUTH, WEST, EAST); + + static { + link(UP, DOWN); + link(NORTH, SOUTH); + link(WEST, EAST); + } + + public static ImmutableList getFaces() { + return ALL_FACES; + } + + private static void link(RelFace a, RelFace b) { + a.counterFace = b; + b.counterFace = a; + } + + public static ImmutableMap mapToFaces( + E up, + E down, + E north, + E south, + E west, + E east + ) { + return ImmutableMap.builderWithExpectedSize(6) + .put(UP, up) + .put(DOWN, down) + .put(NORTH, north) + .put(SOUTH, south) + .put(WEST, west) + .put(EAST, east) + .build(); + } + + public static ImmutableMap mapToFaces(Function generator) { + return mapToFaces( + generator.apply(UP), + generator.apply(DOWN), + generator.apply(NORTH), + generator.apply(SOUTH), + generator.apply(WEST), + generator.apply(EAST) + ); + } + + private static int nextId = 0; + + private final int id; + private final String name; + private RelFace counterFace; + + private RelFace(int x, int y, int z, String name) { + super(x, y, z, false); + this.id = nextId++; + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public AbsFace resolve(AbsFace up) { + return BlockFaceResolver.resolve(this, up); + } + + @Override + public RelFace relativize(AbsFace up) { + return this; + } + + public RelFace rotate(AbsFace fromUp, AbsFace toUp) { + if (fromUp == toUp) { + return this; + } + + return resolve(fromUp).relativize(toUp); + } + + /** + * @return the id + */ + public int getId() { + return id; + } + + public RelFace getCounter() { + return counterFace; + } + + public RelFace getCounterAndMoveCursor(Vec3i cursor) { + cursor.add(getRelVector()); + return counterFace; + } + + @Override + public float getEuclideanDistance() { + return 1.0f; + } + + @Override + public int getChebyshevDistance() { + return 1; + } + + @Override + public int getManhattanDistance() { + return 1; + } + + @Override + public String toString() { + return getName(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java b/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java new file mode 100644 index 0000000..6eec211 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java @@ -0,0 +1,149 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.rels; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.Vectors; + +/** + * Name stands for Relative Relation + */ +public class RelRelation extends BlockRelation { + + private final Vec3i vector = new Vec3i(); + private final Vec3 floatVector = new Vec3(); + private final Vec3 normalized = new Vec3(); + + private AbsRelation[] resolved = null; + + public RelRelation(int north, int west, int up) { + this(north, west, up, false); + } + + public RelRelation(Vec3i vector) { + this(vector.x, vector.y, vector.z, false); + } + + protected RelRelation(int north, int west, int up, boolean precomputeAllResolutions) { + vector.set(north, west, up); + floatVector.set(north, west, up); + normalized.set(north, west, up); + + if (normalized.any()) { + normalized.normalize(); + } + + if (precomputeAllResolutions) { + for (AbsFace face : AbsFace.getFaces()) { + resolve(face); + } + } + } + + public static RelRelation of(Vec3i vector) { + return of(vector.x, vector.y, vector.z); + } + + public static RelRelation of(int north, int west, int up) { + if (Math.abs(north) + Math.abs(west) + Math.abs(up) == 1) { + if (up == 1) { + return RelFace.UP; + } else if (up == -1) { + return RelFace.DOWN; + } else if (north == 1) { + return RelFace.NORTH; + } else if (north == -1) { + return RelFace.SOUTH; + } else if (west == 1) { + return RelFace.WEST; + } else { + assert west == -1; + return RelFace.EAST; + } + } + + return new RelRelation(north, west, up); + } + + /** + * @return the relative vector (northward, westward, upward) + */ + public Vec3i getRelVector() { + return vector; + } + + public Vec3 getRelFloatVector() { + return floatVector; + } + + public Vec3 getRelNormalized() { + return normalized; + } + + public int getNorthward() { + return vector.x; + } + + public int getWestward() { + return vector.y; + } + + public int getUpward() { + return vector.z; + } + + public int getSouthward() { + return -getNorthward(); + } + + public int getEastward() { + return -getWestward(); + } + + public int getDownward() { + return -getUpward(); + } + + @Override + public AbsRelation resolve(AbsFace up) { + if (resolved == null) { + resolved = new AbsRelation[AbsFace.BLOCK_FACE_COUNT]; + } + + if (resolved[up.getId()] == null) { + resolved[up.getId()] = computeResolution(up); + } + + return resolved[up.getId()]; + } + + private AbsRelation computeResolution(AbsFace up) { + Vec3i resolution = Vectors.grab3i(); + AxisRotations.resolve(vector, up, resolution); + AbsRelation result = AbsRelation.of(resolution); + Vectors.release(resolution); + return result; + } + + @Override + protected Vec3i getSample() { + return getRelVector(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java index 650b4a7..a7fa26e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.tile; import java.io.DataInput; @@ -24,8 +24,8 @@ import java.io.IOException; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class PacketAddTile extends PacketAffectTile { @@ -43,8 +43,8 @@ public class PacketAddTile extends PacketAffectTile { return tileId; } - public void set(TileData tile, Vec3i blockInWorld, BlockFace face) { - super.set(blockInWorld, face, -1); + public void set(TileData tile, Vec3i blockInWorld, AbsFace face) { + super.set(blockInWorld, face, TAG_NOT_APPLICABLE); this.tileId = tile.getId(); } @@ -61,7 +61,7 @@ public class PacketAddTile extends PacketAffectTile { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { TileData tile = TileDataRegistry.getInstance().get(getTileId()); world.getTiles(getBlockInWorld(), getFace()).add(tile); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java index b12012c..747dfa6 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.tile; import java.io.DataInput; @@ -26,14 +26,20 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.PacketAffectChunk; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public abstract class PacketAffectTile extends PacketAffectChunk { private final Vec3i blockInWorld = new Vec3i(); - private BlockFace face; + private AbsFace face; private int tag; + /** + * Indicates to the safeguards in {@link #set(Vec3i, AbsFace, int)} that the + * concept of a tile tag is not applicable to this action. + */ + protected static final int TAG_NOT_APPLICABLE = -2; + public PacketAffectTile(String id) { super(id); } @@ -42,7 +48,7 @@ public abstract class PacketAffectTile extends PacketAffectChunk { return blockInWorld; } - public BlockFace getFace() { + public AbsFace getFace() { return face; } @@ -50,7 +56,11 @@ public abstract class PacketAffectTile extends PacketAffectChunk { return tag; } - public void set(Vec3i blockInWorld, BlockFace face, int tag) { + public void set(Vec3i blockInWorld, AbsFace face, int tag) { + if (tag < 0 && tag != TAG_NOT_APPLICABLE) { + throw new IllegalArgumentException("Cannot affect tile with tag " + tag); + } + this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); this.face = face; this.tag = tag; @@ -59,7 +69,7 @@ public abstract class PacketAffectTile extends PacketAffectChunk { @Override public void read(DataInput input) throws IOException, DecodingException { this.blockInWorld.set(input.readInt(), input.readInt(), input.readInt()); - this.face = BlockFace.getFaces().get(input.readByte()); + this.face = AbsFace.getFaces().get(input.readByte()); this.tag = input.readInt(); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java index 9a8ef6c..f98dc63 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.tile; import java.io.DataInput; @@ -25,8 +25,9 @@ import java.io.IOException; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class PacketRemoveTile extends PacketAffectTile { @@ -39,7 +40,7 @@ public class PacketRemoveTile extends PacketAffectTile { } @Override - public void set(Vec3i blockInWorld, BlockFace face, int tag) { + public void set(Vec3i blockInWorld, AbsFace face, int tag) { super.set(blockInWorld, face, tag); } @@ -54,21 +55,14 @@ public class PacketRemoveTile extends PacketAffectTile { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { TileDataStack stack = world.getTiles(getBlockInWorld(), getFace()); int index = stack.getIndexByTag(getTag()); if (index < 0) { - throw CrashReports.report( - null, - "Could not find tile with tag %d at (%d; %d; %d; %s)", - getTag(), - getBlockInWorld().x, - getBlockInWorld().y, - getBlockInWorld().z, - getFace() - ); + throw CrashReports.report(null, "Could not find tile with tag %d at (%d; %d; %d; %s)", getTag(), + getBlockInWorld().x, getBlockInWorld().y, getBlockInWorld().z, getFace()); } stack.remove(index); diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java index d314445..8397be9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java @@ -15,13 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.tile; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.generic.TileGeneric; -public class TileData extends Namespaced implements GenericTile { +public class TileData extends Namespaced implements TileGeneric { public TileData(String id) { super(id); diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataRegistry.java index 110baea..5508ded 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.tile; import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileStackIsFullException.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileStackIsFullException.java index c9f6240..8db0b55 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileStackIsFullException.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileStackIsFullException.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.tile; public class TileStackIsFullException extends RuntimeException { @@ -26,12 +26,8 @@ public class TileStackIsFullException extends RuntimeException { } - public TileStackIsFullException( - String message, - Throwable cause, - boolean enableSuppression, - boolean writableStackTrace - ) { + public TileStackIsFullException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } diff --git a/src/main/java/ru/windcorp/progressia/server/ChunkLoader.java b/src/main/java/ru/windcorp/progressia/server/ChunkLoader.java index d708fe2..f2391a2 100644 --- a/src/main/java/ru/windcorp/progressia/server/ChunkLoader.java +++ b/src/main/java/ru/windcorp/progressia/server/ChunkLoader.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/progressia/server/ChunkManager.java b/src/main/java/ru/windcorp/progressia/server/ChunkManager.java deleted file mode 100644 index b0b0777..0000000 --- a/src/main/java/ru/windcorp/progressia/server/ChunkManager.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.server; - -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.PacketRevokeChunk; -import ru.windcorp.progressia.common.world.PacketSendChunk; -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.generic.ChunkSet; -import ru.windcorp.progressia.common.world.generic.ChunkSets; -import ru.windcorp.progressia.test.TestWorldDiskIO; - -public class ChunkManager { - - private class PlayerVision { - - private final ChunkSet visible = ChunkSets.newSyncHashSet(); - private final ChunkSet requested = ChunkSets.newHashSet(); - private final ChunkSet toSend = ChunkSets.newHashSet(); - private final ChunkSet toRevoke = ChunkSets.newHashSet(); - - public boolean isChunkVisible(Vec3i chunkPos) { - return visible.contains(chunkPos); - } - - public void gatherRequests(Player player) { - requested.clear(); - player.requestChunksToLoad(requested::add); - } - - public void updateQueues(Player player) { - toSend.clear(); - - requested.forEachIn(server.getWorld(), chunk -> { - if (!chunk.isReady()) - return; - if (visible.contains(chunk)) - return; - toSend.add(chunk); - }); - - toRevoke.clear(); - toRevoke.addAll(visible); - toRevoke.removeIf(v -> loaded.contains(v) && requested.contains(v)); - } - - public void processQueues(Player player) { - toRevoke.forEach(chunkPos -> revokeChunk(player, chunkPos)); - toRevoke.clear(); - - toSend.forEach(chunkPos -> sendChunk(player, chunkPos)); - toSend.clear(); - } - - } - - private final Server server; - - private final ChunkSet loaded; - private final ChunkSet requested = ChunkSets.newHashSet(); - private final ChunkSet toLoad = ChunkSets.newHashSet(); - private final ChunkSet toUnload = ChunkSets.newHashSet(); - - // TODO replace with a normal Map managed by some sort of PlayerListener, - // weak maps are weak - private final Map visions = Collections.synchronizedMap(new WeakHashMap<>()); - - public ChunkManager(Server server) { - this.server = server; - this.loaded = server.getWorld().getData().getLoadedChunks(); - } - - public void tick() { - synchronized (getServer().getWorld().getData()) { - synchronized (visions) { - gatherRequests(); - updateQueues(); - processQueues(); - } - } - } - - private void gatherRequests() { - requested.clear(); - - server.getPlayerManager().getPlayers().forEach(p -> { - PlayerVision vision = getVision(p, true); - vision.gatherRequests(p); - requested.addAll(vision.requested); - }); - } - - private void updateQueues() { - toLoad.clear(); - toLoad.addAll(requested); - toLoad.removeAll(loaded); - - toUnload.clear(); - toUnload.addAll(loaded); - toUnload.removeAll(requested); - - visions.forEach((p, v) -> { - v.updateQueues(p); - }); - } - - private void processQueues() { - toUnload.forEach(this::unloadChunk); - toUnload.clear(); - toLoad.forEach(this::loadChunk); - toLoad.clear(); - - visions.forEach((p, v) -> { - v.processQueues(p); - }); - } - - private PlayerVision getVision(Player player, boolean createIfMissing) { - return createIfMissing ? visions.computeIfAbsent(player, k -> new PlayerVision()) : visions.get(player); - } - - public void loadChunk(Vec3i chunkPos) { - - WorldData world = getServer().getWorld().getData(); - - ChunkData chunk = TestWorldDiskIO.tryToLoad(chunkPos, world, getServer()); - if (chunk != null) { - world.addChunk(chunk); - } else { - getServer().getWorld().generate(chunkPos); - } - - } - - public void unloadChunk(Vec3i chunkPos) { - - WorldData world = getServer().getWorld().getData(); - - ChunkData chunk = world.getChunk(chunkPos); - if (chunk == null) { - throw new IllegalStateException( - String.format( - "Chunk (%d; %d; %d) not loaded, cannot unload", - chunkPos.x, - chunkPos.y, - chunkPos.z - ) - ); - } - - world.removeChunk(chunk); - - TestWorldDiskIO.saveChunk(chunk, getServer()); - - } - - public void sendChunk(Player player, Vec3i chunkPos) { - ChunkData chunk = server.getWorld().getData().getChunk(chunkPos); - - if (chunk == null) { - throw new IllegalStateException( - String.format( - "Chunk (%d; %d; %d) is not loaded, cannot send", - chunkPos.x, - chunkPos.y, - chunkPos.z - ) - ); - } - - PacketSendChunk packet = new PacketSendChunk(); - packet.set(chunk); - player.getClient().sendPacket(packet); - - getVision(player, true).visible.add(chunkPos); - } - - public void revokeChunk(Player player, Vec3i chunkPos) { - PacketRevokeChunk packet = new PacketRevokeChunk(); - packet.set(chunkPos); - player.getClient().sendPacket(packet); - - PlayerVision vision = getVision(player, false); - if (vision != null) { - vision.visible.remove(chunkPos); - } - } - - public boolean isChunkVisible(Vec3i chunkPos, Player player) { - PlayerVision vision = getVision(player, false); - - if (vision == null) { - return false; - } - - return vision.isChunkVisible(chunkPos); - } - - public ChunkSet getVisibleChunks(Player player) { - PlayerVision vision = getVision(player, false); - - if (vision == null) { - return ChunkSets.empty(); - } - - return vision.visible; - } - - public Server getServer() { - return server; - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/EntityManager.java b/src/main/java/ru/windcorp/progressia/server/EntityManager.java deleted file mode 100644 index d904c83..0000000 --- a/src/main/java/ru/windcorp/progressia/server/EntityManager.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.server; - -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; - -import glm.vec._3.i.Vec3i; -import gnu.trove.TCollections; -import gnu.trove.iterator.TLongIterator; -import gnu.trove.set.TLongSet; -import gnu.trove.set.hash.TLongHashSet; -import ru.windcorp.jputil.chars.StringUtil; -import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.entity.PacketRevokeEntity; -import ru.windcorp.progressia.common.world.entity.PacketSendEntity; -import ru.windcorp.progressia.common.world.generic.ChunkSet; - -public class EntityManager { - - private class PlayerVision { - - private final TLongSet visible = TCollections.synchronizedSet(new TLongHashSet()); - private final TLongSet requested = new TLongHashSet(); - private final TLongSet toSend = new TLongHashSet(); - private final TLongSet toRevoke = new TLongHashSet(); - - public boolean isEntityVisible(long entityId) { - return visible.contains(entityId); - } - - public void gatherRequests(Player player) { - requested.clear(); - - ChunkSet visibleChunks = player.getClient().getVisibleChunks(); - Vec3i v = Vectors.grab3i(); - - getServer().getWorld().forEachEntity(entity -> { - if (visibleChunks.contains(entity.getChunkCoords(v))) { - requested.add(entity.getEntityId()); - } - }); - - Vectors.release(v); - } - - public void updateQueues(Player player) { - toSend.clear(); - toSend.addAll(requested); - toSend.removeAll(visible); - toSend.retainAll(loaded); - - toRevoke.clear(); - - for (TLongIterator it = visible.iterator(); it.hasNext();) { - long entityId = it.next(); - if (!loaded.contains(entityId) || !requested.contains(entityId)) { - toRevoke.add(entityId); - } - } - } - - public void processQueues(Player player) { - toRevoke.forEach(entityId -> { - revokeEntity(player, entityId); - return true; - }); - toRevoke.clear(); - - toSend.forEach(entityId -> { - sendEntity(player, entityId); - return true; - }); - toSend.clear(); - } - - } - - private final Server server; - - private final TLongSet loaded; - - // TODO replace with a normal Map managed by some sort of PlayerListener, - // weak maps are weak - private final Map visions = Collections.synchronizedMap(new WeakHashMap<>()); - - public EntityManager(Server server) { - this.server = server; - this.loaded = server.getWorld().getData().getLoadedEntities(); - } - - public void tick() { - synchronized (getServer().getWorld().getData()) { - synchronized (visions) { - gatherRequests(); - updateQueues(); - processQueues(); - } - } - } - - private void gatherRequests() { - server.getPlayerManager().getPlayers().forEach(p -> { - PlayerVision vision = getVision(p, true); - vision.gatherRequests(p); - }); - } - - private void updateQueues() { - visions.forEach((p, v) -> { - v.updateQueues(p); - }); - } - - private void processQueues() { - visions.forEach((p, v) -> { - v.processQueues(p); - }); - } - - private PlayerVision getVision(Player player, boolean createIfMissing) { - return createIfMissing ? visions.computeIfAbsent(player, k -> new PlayerVision()) : visions.get(player); - } - - public void sendEntity(Player player, long entityId) { - - EntityData entity = server.getWorld().getData().getEntity(entityId); - - if (entity == null) { - throw new IllegalStateException( - "Entity with entity ID " + new String(StringUtil.toFullHex(entityId)) + " is not loaded, cannot send" - ); - } - - PacketSendEntity packet = new PacketSendEntity(); - packet.set(entity); - player.getClient().sendPacket(packet); - - getVision(player, true).visible.add(entityId); - } - - public void revokeEntity(Player player, long entityId) { - PacketRevokeEntity packet = new PacketRevokeEntity(); - packet.set(entityId); - player.getClient().sendPacket(packet); - - PlayerVision vision = getVision(player, false); - if (vision != null) { - vision.visible.remove(entityId); - } - } - - public boolean isEntityVisible(long entityId, Player player) { - PlayerVision vision = getVision(player, false); - - if (vision == null) { - return false; - } - - return vision.isEntityVisible(entityId); - } - - private static final TLongSet EMPTY_LONG_SET = TCollections.unmodifiableSet(new TLongHashSet()); - - public TLongSet getVisibleEntities(Player player) { - PlayerVision vision = getVision(player, false); - - if (vision == null) { - return EMPTY_LONG_SET; - } - - return vision.visible; - } - - public Server getServer() { - return server; - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/Player.java b/src/main/java/ru/windcorp/progressia/server/Player.java index ea373a8..89fbebc 100644 --- a/src/main/java/ru/windcorp/progressia/server/Player.java +++ b/src/main/java/ru/windcorp/progressia/server/Player.java @@ -15,14 +15,18 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server; import java.util.function.Consumer; +import glm.mat._3.Mat3; +import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.Units; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.util.Matrices; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.PlayerData; import ru.windcorp.progressia.common.world.entity.EntityData; @@ -55,15 +59,40 @@ public class Player extends PlayerData implements ChunkLoader { Coordinates.convertInWorldToChunk(start, start); Vec3i cursor = new Vec3i(); - float radius = getServer().getLoadDistance(this) / Units.get(ChunkData.BLOCKS_PER_CHUNK, "m"); + float radius = getServer().getLoadDistance(this) / Units.get(DefaultChunkData.BLOCKS_PER_CHUNK, "m"); float radiusSq = radius * radius; int iRadius = (int) Math.ceil(radius); + // The sphere around the player is stretched by this factor vertically + // (along the player's up vector) + final float verticalStretching = 0.4f; + + float factor = (1/verticalStretching - 1); + Vec3 up = getServer().getWorld().getData().getGravityModel().getUp(getEntity().getPosition(), null); + + Mat3 transform = Matrices.grab3(); + + //@formatter:off + transform.set( + 1 + factor * up.x * up.x, 0 + factor * up.x * up.y, 0 + factor * up.x * up.z, + 0 + factor * up.y * up.x, 1 + factor * up.y * up.y, 0 + factor * up.y * up.z, + 0 + factor * up.z * up.x, 0 + factor * up.z * up.y, 1 + factor * up.z * up.z + ); + //@formatter:on + + Vec3 transformedCursor = Vectors.grab3(); + for (cursor.x = -iRadius; cursor.x <= +iRadius; ++cursor.x) { for (cursor.y = -iRadius; cursor.y <= +iRadius; ++cursor.y) { for (cursor.z = -iRadius; cursor.z <= +iRadius; ++cursor.z) { - if (cursor.x * cursor.x + cursor.y * cursor.y + (cursor.z * 2) * (cursor.z * 2) <= radiusSq) { + + transformedCursor.set(cursor.x, cursor.y, cursor.z); + + // .mul(Vec3) is cursed + transform.mul(transformedCursor, transformedCursor); + + if (transformedCursor.dot(transformedCursor) <= radiusSq) { cursor.add(start); chunkConsumer.accept(cursor); @@ -73,6 +102,9 @@ public class Player extends PlayerData implements ChunkLoader { } } } + + Matrices.release(transform); + Vectors.release(transformedCursor); } public String getLogin() { diff --git a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java index 38d0f32..f762778 100644 --- a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java +++ b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java @@ -22,10 +22,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import glm.vec._2.Vec2; +import glm.vec._3.Vec3; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityDataRegistry; +import ru.windcorp.progressia.server.events.PlayerJoinedEvent; import ru.windcorp.progressia.test.TestContent; public class PlayerManager { @@ -44,6 +45,7 @@ public class PlayerManager { public void addPlayer(Player player) { this.players.add(player); + getServer().postEvent(new PlayerJoinedEvent.Immutable(getServer(), player)); } public EntityData conjurePlayerEntity(String login) { @@ -60,18 +62,19 @@ public class PlayerManager { EntityData player = EntityDataRegistry.getInstance().create("Test:Player"); player.setEntityId(TestContent.PLAYER_ENTITY_ID); - player.setPosition(TestContent.SPAWN); - player.setDirection( - new Vec2( - Math.toRadians(40), - Math.toRadians(10) - ) - ); + player.setPosition(getServer().getWorld().getGenerator().suggestSpawnLocation()); + + player.setUpVector(new Vec3(0, 0, 1)); + player.setLookingAt(new Vec3(2, 1, 0)); getServer().getWorld().getData().addEntity(player); return player; } + + public Object getMutex() { + return players; + } public Server getServer() { return server; diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index 487616d..c3cbb03 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -18,20 +18,50 @@ package ru.windcorp.progressia.server; +import java.util.List; +import java.util.Random; import java.util.function.Consumer; +import java.util.function.Function; import org.apache.logging.log4j.LogManager; +import com.google.common.eventbus.EventBus; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; import ru.windcorp.jputil.functions.ThrowingRunnable; import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.util.TaskQueue; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.util.crash.ReportingEventBus; +import ru.windcorp.progressia.common.world.ChunkDataListener; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.common.world.GravityModelRegistry; +import ru.windcorp.progressia.common.world.WorldDataListener; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.server.comms.ClientManager; -import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.events.ServerEvent; +import ru.windcorp.progressia.server.management.load.ChunkRequestDaemon; +import ru.windcorp.progressia.server.management.load.EntityRequestDaemon; +import ru.windcorp.progressia.server.management.load.LoadManager; +import ru.windcorp.progressia.server.world.DefaultWorldLogic; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; +import ru.windcorp.progressia.server.world.context.impl.DefaultServerContext; +import ru.windcorp.progressia.server.world.context.impl.ReportingServerContext; +import ru.windcorp.progressia.server.world.context.impl.RotatingServerContext; +import ru.windcorp.progressia.server.world.generation.WorldGenerator; import ru.windcorp.progressia.server.world.tasks.WorldAccessor; import ru.windcorp.progressia.server.world.ticking.Change; import ru.windcorp.progressia.server.world.ticking.Evaluation; -import ru.windcorp.progressia.test.gen.TestWorldGenerator; +import ru.windcorp.progressia.server.world.ticking.TickerCoordinator; +import ru.windcorp.progressia.test.TestEntityDataFallingBlock; +import ru.windcorp.progressia.test.TestEntityLogicFallingBlock; public class Server { @@ -45,46 +75,171 @@ public class Server { return ServerThread.getCurrentServer(); } - private final WorldLogic world; + private final DefaultWorldLogic world; private final WorldAccessor worldAccessor = new WorldAccessor(this); private final ServerThread serverThread; private final ClientManager clientManager; private final PlayerManager playerManager; - private final ChunkManager chunkManager; - private final EntityManager entityManager; + private final LoadManager loadManager; private final TaskQueue taskQueue = new TaskQueue(this::isServerThread); + private final EventBus eventBus = ReportingEventBus.create("ServerEvents"); + private final TickingSettings tickingSettings = new TickingSettings(); - public Server(WorldData world) { - this.world = new WorldLogic(world, this, TestWorldGenerator::new); + public Server(DefaultWorldData world, Function generatorCreator) { + world.addListener(new WorldDataListener() { + @Override + public void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { + //PlanetGenerator.this.planet; + //LogManager.getLogger().info("Loaded chunk"); + GravityModelRegistry.getInstance().get("Test:PlanetGravityModel"); + chunk.addListener(new ChunkDataListener() { // Falling Block + // spawning logic + @Override + public void onChunkBlockChanged(DefaultChunkData chunk_2, Vec3i blockInChunk, BlockData previous, + BlockData current) { + Vec3i chunkWorldPos = new Vec3i(0,0,0); + Coordinates.getInWorld(chunk_2.getPosition(), blockInChunk, chunkWorldPos); + + /*List underBlocks = getGoodCardinals(fallBlock.getUpVector().negate_()); + + boolean notSupported = false; + for (Vec3i v3 : underBlocks) + { + Vec3i inWorld = occupiedBlock.sub_(v3); + if (context.getBlock(inWorld).getId()=="Test:Air") { + notSupported=true; + break; + } + }*/ + + //chunk.getPosition().mul_(16).add_(blockInChunk); + //LogManager.getLogger().info("Put block {} at {}<{}<{}",current.getId(),chunkWorldPos.x,chunkWorldPos.y,chunkWorldPos.z); + + if (TestEntityLogicFallingBlock.FallingBlocks + .contains(chunk_2.getWorld().getBlock(chunkWorldPos.add_(0, 0, 1)).getId())) { + chunk_2.getWorld().setBlock(chunkWorldPos.add_(0, 0, 1), BlockDataRegistry.getInstance() + .get(chunk_2.getWorld().getBlock(chunkWorldPos.add_(0, 0, 1)).getId()), true); + } + if (!TestEntityLogicFallingBlock.FallingBlocks.contains(current.getId())) { + return; + } + //LogManager.getLogger().info("Cont"); + if (chunk_2.getWorld().getBlock(chunkWorldPos.add_(0, 0, -1)).getId() == "Test:Air") { + LogManager.getLogger().info("Inserting FallingBlock {},{},{}", + chunkWorldPos.x,chunkWorldPos.y,chunkWorldPos.z); + + TestEntityDataFallingBlock fallingBlock = new TestEntityDataFallingBlock(current); + + Vec3i worldPos = chunk_2.getPosition().mul_(16).add_(blockInChunk); + Vec3 floatWorldPos = new Vec3(worldPos.x, worldPos.y, worldPos.z); + fallingBlock.setPosition(floatWorldPos); + + fallingBlock.setEntityId(("Test:FallingBlock" + floatWorldPos.toString() + + String.valueOf(new Random().nextFloat())).hashCode()); + + chunk.getWorld().addEntity(fallingBlock); + //invokeLater(() -> world.addEntity(fallingBlock)); + + //chunk.setBlock(blockInChunk, previous, false); + //invokeLater(() -> world.setBlock(chunkWorldPos, BlockDataRegistry.getInstance().get("Test:Air"), false)); + + + //LogManager.getLogger().info(String.valueOf(chunkWorldPos.x) + " " + // + String.valueOf(chunkWorldPos.y) + " " + String.valueOf(chunkWorldPos.z)); + } + } + }); + } + }); + this.world = new DefaultWorldLogic( + world, + this, + generatorCreator.apply(this), + worldAccessor + ); this.serverThread = new ServerThread(this); this.clientManager = new ClientManager(this); this.playerManager = new PlayerManager(this); - this.chunkManager = new ChunkManager(this); - this.entityManager = new EntityManager(this); + this.loadManager = new LoadManager(this); + schedule(new ChunkRequestDaemon(loadManager.getChunkManager())::tick); + schedule(new EntityRequestDaemon(loadManager.getEntityManager())::tick); + + // Must run after request daemons so it only schedules chunks that + // hadn't unloaded schedule(this::scheduleWorldTicks); - schedule(chunkManager::tick); - schedule(entityManager::tick); } /** * Returns this server's world. * - * @return this server's {@link WorldLogic} + * @return this server's {@link DefaultWorldLogic} */ - public WorldLogic getWorld() { + public DefaultWorldLogic getWorld() { return world; } /** - * Returns this server's {@link ClientManager}. - * Use this to deal with communications, e.g. send packets. + * Instantiates and returns an new {@link ServerWorldContext} instance + * suitable for read and write access to the server's world. This context + * uses the absolute coordinate space (not rotated to match positive Z = + * up). + * + * @return the context + * @see #createContext(AbsFace) + */ + public ServerWorldContext createAbsoluteContext() { + return doCreateAbsoluteContext(); + } + + private ServerTileContext doCreateAbsoluteContext() { + return new ReportingServerContext(DefaultServerContext.empty().inRealWorldOf(this).build()) + .withListener(worldAccessor).setPassToParent(false); + } + + /** + * Instantiates and returns an new {@link ServerWorldContext} instance + * suitable for read and write access to the server's world. This is the + * preferred way to query or change the world. This context uses the + * coordinate space in which positive Z = {@code up}. + * + * @param up the desired up direction + * @return the context + * @see #createContext(Vec3i) + * @see #createAbsoluteContext() + */ + public ServerWorldContext createContext(AbsFace up) { + return new RotatingServerContext(doCreateAbsoluteContext(), up); + } + + /** + * Instantiates and returns an new {@link ServerBlockContext} instance + * suitable for read and write access to the server's world. The context is + * initialized to point to the provided block. This is the preferred way to + * query or change the world. This context uses the coordinate space in + * which positive Z matches the discrete up direction of the provided + * location. + * + * @param up the desired up direction + * @return the context + * @see #createContext(AbsFace) + * @see #createAbsoluteContext() + */ + public ServerBlockContext createContext(Vec3i blockInWorld) { + AbsFace up = getWorld().getUp(blockInWorld); + Vec3i relativeBlockInWorld = AxisRotations.relativize(blockInWorld, up, null); + return new RotatingServerContext(doCreateAbsoluteContext(), up).push(relativeBlockInWorld); + } + + /** + * Returns this server's {@link ClientManager}. Use this to deal with + * communications, e.g. send packets. * * @return the {@link ClientManager} that handles this server */ @@ -96,8 +251,8 @@ public class Server { return playerManager; } - public ChunkManager getChunkManager() { - return chunkManager; + public LoadManager getLoadManager() { + return loadManager; } /** @@ -110,9 +265,9 @@ public class Server { } /** - * Requests that the provided task is executed once on next server tick. - * The task will be run in the main server thread. The task object is - * discarded after execution. + * Requests that the provided task is executed once on next server tick. The + * task will be run in the main server thread. The task object is discarded + * after execution. *

    * Use this method to request a one-time (rare) action that must necessarily * happen in the main server thread, such as initialization tasks or @@ -129,13 +284,12 @@ public class Server { /** * Executes the tasks in the server main thread as soon as possible. *

    - * If this method is invoked in the server main thread, then the task is - * run immediately (the method blocks until the task finishes). Otherwise - * this method behaves exactly like {@link #invokeLater(Runnable)}. + * If this method is invoked in the server main thread, then the task is run + * immediately (the method blocks until the task finishes). Otherwise this + * method behaves exactly like {@link #invokeLater(Runnable)}. *

    * Use this method to make sure that a piece of code is run in the main - * server - * thread. + * server thread. * * @param task the task to run * @see #invokeLater(Runnable) @@ -145,11 +299,7 @@ public class Server { taskQueue.invokeNow(task); } - public void waitAndInvoke( - ThrowingRunnable task - ) - throws InterruptedException, - E { + public void waitAndInvoke(ThrowingRunnable task) throws InterruptedException, E { taskQueue.waitAndInvoke(task); } @@ -161,13 +311,55 @@ public class Server { schedule(() -> task.accept(this)); } - public void requestChange(Change change) { + /** + * Delayed + */ + public void scheduleChange(Change change) { serverThread.getTicker().requestChange(change); } - - public void requestEvaluation(Evaluation evaluation) { + + /** + * Delayed + */ + public void scheduleEvaluation(Evaluation evaluation) { serverThread.getTicker().requestEvaluation(evaluation); } + + /** + * Immediate if possible, otherwise delayed + */ + public void requestChange(Change change) { + if (serverThread.getTicker().getPhase() == TickerCoordinator.TickPhase.SYNCHRONOUS) { + change.affect(this); + } else { + serverThread.getTicker().requestChange(change); + } + } + + /** + * Immediate if possible, otherwise delayed + */ + public void requestEvaluation(Evaluation evaluation) { + if (serverThread.getTicker().getPhase() == TickerCoordinator.TickPhase.SYNCHRONOUS) { + evaluation.evaluate(this); + } else { + serverThread.getTicker().requestEvaluation(evaluation); + } + } + + public void subscribe(Object object) { + eventBus.register(object); + } + + public void unsubscribe(Object object) { + eventBus.unregister(object); + } + + public void postEvent(ServerEvent event) { + event.setServer(this); + eventBus.post(event); + event.setServer(null); + } /** * Returns the duration of the last server tick. Server logic should assume @@ -195,19 +387,6 @@ public class Server { return this.serverThread.getTicker().getUptimeTicks(); } - /** - * Returns the {@link WorldAccessor} object for this server. Use the - * provided accessor to - * request common {@link Evaluation}s and {@link Change}s. - * - * @return a {@link WorldAccessor} - * @see #requestChange(Change) - * @see #requestEvaluation(Evaluation) - */ - public WorldAccessor getWorldAccessor() { - return worldAccessor; - } - /** * Returns the ticking settings for this server. * @@ -218,7 +397,7 @@ public class Server { } public float getLoadDistance(Player player) { - return Units.get(150.0f, "m"); + return Units.get(100.5f, "m"); } /** @@ -238,8 +417,7 @@ public class Server { /** * Shuts the server down, disconnecting the clients with the provided - * message. - * This method blocks until the shutdown is complete. + * message. This method blocks until the shutdown is complete. * * @param message the message to send to the clients as the disconnect * reason @@ -250,16 +428,15 @@ public class Server { } private void scheduleWorldTicks(Server server) { - server.getWorld().getChunks().forEach(chunk -> requestEvaluation(chunk.getTickTask())); - requestEvaluation(server.getWorld().getTickEntitiesTask()); + server.getWorld().getChunks().forEach(chunk -> scheduleEvaluation(chunk.getTickTask())); + scheduleEvaluation(server.getWorld().getTickEntitiesTask()); } /** * Returns an instance of {@link java.util.Random Random} that can be used - * as a source of indeterministic - * randomness. World generation and other algorithms that must have random - * but reproducible results should - * not use this. + * as a source of indeterministic randomness. World generation and other + * algorithms that must have random but reproducible results should not use + * this. * * @return a thread-safe indeterministic instance of * {@link java.util.Random}. diff --git a/src/main/java/ru/windcorp/progressia/server/ServerState.java b/src/main/java/ru/windcorp/progressia/server/ServerState.java index 774f17d..caa9792 100644 --- a/src/main/java/ru/windcorp/progressia/server/ServerState.java +++ b/src/main/java/ru/windcorp/progressia/server/ServerState.java @@ -15,10 +15,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.test.gen.TestGenerationConfig; public class ServerState { @@ -33,7 +34,7 @@ public class ServerState { } public static void startServer() { - Server server = new Server(new WorldData()); + Server server = new Server(new DefaultWorldData(), TestGenerationConfig.createGenerator()); setInstance(server); server.start(); } diff --git a/src/main/java/ru/windcorp/progressia/server/ServerThread.java b/src/main/java/ru/windcorp/progressia/server/ServerThread.java index 90f3ce9..2cf3296 100644 --- a/src/main/java/ru/windcorp/progressia/server/ServerThread.java +++ b/src/main/java/ru/windcorp/progressia/server/ServerThread.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server; import java.util.concurrent.Executors; @@ -51,9 +51,8 @@ public class ServerThread implements Runnable { } private final Server server; - private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor( - r -> new Thread(new ServerThreadTracker(r), "Server thread") - ); + private final ScheduledExecutorService executor = Executors + .newSingleThreadScheduledExecutor(r -> new Thread(new ServerThreadTracker(r), "Server thread")); private final TickerCoordinator ticker; diff --git a/src/main/java/ru/windcorp/progressia/server/TickingSettings.java b/src/main/java/ru/windcorp/progressia/server/TickingSettings.java index 743da10..8cb77d6 100644 --- a/src/main/java/ru/windcorp/progressia/server/TickingSettings.java +++ b/src/main/java/ru/windcorp/progressia/server/TickingSettings.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server; import ru.windcorp.progressia.common.Units; diff --git a/src/main/java/ru/windcorp/progressia/server/comms/Client.java b/src/main/java/ru/windcorp/progressia/server/comms/Client.java index f439e27..fdc1e98 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/Client.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/Client.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.comms; import ru.windcorp.progressia.common.comms.CommsChannel; diff --git a/src/main/java/ru/windcorp/progressia/server/comms/ClientChat.java b/src/main/java/ru/windcorp/progressia/server/comms/ClientChat.java index 35b9ca2..3d46634 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/ClientChat.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/ClientChat.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.comms; public abstract class ClientChat extends Client { diff --git a/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java b/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java index cb4b80b..57ff467 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.comms; import java.util.Collection; @@ -28,6 +28,7 @@ import gnu.trove.map.TIntObjectMap; import gnu.trove.map.hash.TIntObjectHashMap; import ru.windcorp.progressia.common.comms.CommsChannel.State; import ru.windcorp.progressia.common.comms.packets.Packet; +import ru.windcorp.progressia.common.world.PacketSetGravityModel; import ru.windcorp.progressia.common.world.PacketSetLocalPlayer; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.server.Player; @@ -73,10 +74,14 @@ public class ClientManager { private void addClientPlayer(ClientPlayer client) { String login = client.getLogin(); + + PacketSetGravityModel setGravityModelPacket = new PacketSetGravityModel(); + setGravityModelPacket.set(getServer().getWorld().getData().getGravityModel()); + client.sendPacket(setGravityModelPacket); EntityData entity = getServer().getPlayerManager().conjurePlayerEntity(login); Player player = new Player(entity, getServer(), client); - getServer().getPlayerManager().getPlayers().add(player); + getServer().getPlayerManager().addPlayer(player); PacketSetLocalPlayer packet = new PacketSetLocalPlayer(); packet.set(entity.getEntityId()); @@ -91,7 +96,8 @@ public class ClientManager { /** * Sends the provided packet to all connected player clients. * - * @param packet the packet to broadcast + * @param packet + * the packet to broadcast */ public void broadcastToAllPlayers(Packet packet) { getClients().forEach(c -> { @@ -107,8 +113,10 @@ public class ClientManager { * Sends the provided packet to all connected player clients that can see * the chunk identified by {@code chunkPos}. * - * @param packet the packet to broadcast - * @param chunkPos the chunk coordinates of the chunk that must be visible + * @param packet + * the packet to broadcast + * @param chunkPos + * the chunk coordinates of the chunk that must be visible */ public void broadcastLocal(Packet packet, Vec3i chunkPos) { getClients().forEach(c -> { @@ -126,8 +134,10 @@ public class ClientManager { * Sends the provided packet to all connected player clients that can see * the entity identified by {@code entityId}. * - * @param packet the packet to broadcast - * @param entityId the ID of the entity that must be visible + * @param packet + * the packet to broadcast + * @param entityId + * the ID of the entity that must be visible */ public void broadcastLocal(Packet packet, long entityId) { getClients().forEach(c -> { diff --git a/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java b/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java index c455b8e..3a83bb3 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.comms; import glm.vec._3.i.Vec3i; @@ -44,13 +44,13 @@ public abstract class ClientPlayer extends ClientChat { public boolean isChunkVisible(Vec3i chunkPos) { if (player == null) return false; - return player.getServer().getChunkManager().isChunkVisible(chunkPos, player); + return player.getServer().getLoadManager().getVisionManager().isChunkVisible(chunkPos, player); } public ChunkSet getVisibleChunks() { if (player == null) return ChunkSets.empty(); - return player.getServer().getChunkManager().getVisibleChunks(player); + return player.getServer().getLoadManager().getVisionManager().getVisibleChunks(player); } public boolean isChunkVisible(long entityId) { diff --git a/src/main/java/ru/windcorp/progressia/server/comms/DefaultServerCommsListener.java b/src/main/java/ru/windcorp/progressia/server/comms/DefaultServerCommsListener.java index d570e01..bcc51ac 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/DefaultServerCommsListener.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/DefaultServerCommsListener.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.comms; import java.io.IOException; @@ -41,9 +41,8 @@ public class DefaultServerCommsListener implements CommsListener { if (packet instanceof PacketControl) { PacketControl packetControl = (PacketControl) packet; - ControlLogicRegistry.getInstance().get( - packetControl.getControl().getId() - ).apply(manager.getServer(), packetControl, client); + ControlLogicRegistry.getInstance().get(packetControl.getControl().getId()).apply(manager.getServer(), + packetControl, client); } } } diff --git a/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java b/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java index 31e97a2..713ada7 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.comms.controls; import ru.windcorp.progressia.common.comms.controls.PacketControl; @@ -27,22 +27,14 @@ public abstract class ControlLogic extends Namespaced { @FunctionalInterface public static interface Lambda { - void apply( - Server server, - PacketControl packet, - Client client - ); + void apply(Server server, PacketControl packet, Client client); } public ControlLogic(String id) { super(id); } - public abstract void apply( - Server server, - PacketControl packet, - Client client - ); + public abstract void apply(Server server, PacketControl packet, Client client); public static ControlLogic of(String id, Lambda logic) { return new ControlLogic(id) { diff --git a/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogicRegistry.java b/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogicRegistry.java index 18ece0a..92112e3 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogicRegistry.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogicRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.comms.controls; import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContext.java b/src/main/java/ru/windcorp/progressia/server/events/ClientEvent.java similarity index 58% rename from src/main/java/ru/windcorp/progressia/server/world/TickContext.java rename to src/main/java/ru/windcorp/progressia/server/events/ClientEvent.java index 50dda55..c795fa8 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/events/ClientEvent.java @@ -15,35 +15,32 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -package ru.windcorp.progressia.server.world; +package ru.windcorp.progressia.server.events; -import java.util.Random; - -import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.tasks.WorldAccessor; +import ru.windcorp.progressia.server.comms.Client; -public interface TickContext { +public interface ClientEvent extends ServerEvent { + + Client getClient(); + + public static abstract class Immutable extends ServerEvent.Default implements ClientEvent { + + private final Client client; - float getTickLength(); - - Server getServer(); - - default WorldLogic getWorld() { - return getServer().getWorld(); - } - - default WorldAccessor getAccessor() { - return getServer().getWorldAccessor(); - } - - default Random getRandom() { - return getServer().getAdHocRandom(); - } - - default WorldData getWorldData() { - return getWorld().getData(); + public Immutable(Server server, Client client) { + super(server); + this.client = client; + } + + /** + * @return the client + */ + @Override + public Client getClient() { + return client; + } + } } diff --git a/src/main/java/ru/windcorp/progressia/server/events/PlayerEvent.java b/src/main/java/ru/windcorp/progressia/server/events/PlayerEvent.java new file mode 100644 index 0000000..544418e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/events/PlayerEvent.java @@ -0,0 +1,49 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.events; + +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.comms.Client; + +public interface PlayerEvent extends ClientEvent { + + Player getPlayer(); + + public static abstract class Immutable extends ServerEvent.Default implements PlayerEvent { + + private final Player player; + + public Immutable(Server server, Player player) { + super(server); + this.player = player; + } + + @Override + public Player getPlayer() { + return player; + } + + @Override + public Client getClient() { + return player.getClient(); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java b/src/main/java/ru/windcorp/progressia/server/events/PlayerJoinedEvent.java similarity index 65% rename from src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java rename to src/main/java/ru/windcorp/progressia/server/events/PlayerJoinedEvent.java index 5e91963..eed2a90 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java +++ b/src/main/java/ru/windcorp/progressia/server/events/PlayerJoinedEvent.java @@ -15,16 +15,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -package ru.windcorp.progressia.server.world.tile; +package ru.windcorp.progressia.server.events; -import ru.windcorp.progressia.common.world.generic.GenericTileStack; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.server.world.ChunkLogic; +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; -public abstract class TileLogicStack - extends GenericTileStack { +public interface PlayerJoinedEvent extends PlayerEvent { + + public static class Immutable extends PlayerEvent.Immutable implements PlayerJoinedEvent { - public abstract TileDataStack getData(); + public Immutable(Server server, Player player) { + super(server, player); + } + + } } diff --git a/src/main/java/ru/windcorp/progressia/server/events/PlayerLeftEvent.java b/src/main/java/ru/windcorp/progressia/server/events/PlayerLeftEvent.java new file mode 100644 index 0000000..d6e4417 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/events/PlayerLeftEvent.java @@ -0,0 +1,33 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.events; + +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; + +public interface PlayerLeftEvent extends PlayerEvent { + + public static class Immutable extends PlayerEvent.Immutable implements PlayerLeftEvent { + + public Immutable(Server server, Player player) { + super(server, player); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/events/ServerEvent.java b/src/main/java/ru/windcorp/progressia/server/events/ServerEvent.java new file mode 100644 index 0000000..b63f727 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/events/ServerEvent.java @@ -0,0 +1,68 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.events; + +import ru.windcorp.progressia.server.Server; + +/** + * An interface for all events issued by a {@link Server}. + */ +public interface ServerEvent { + + /** + * Returns the server instance that this event happened on. + * + * @return the relevant server + */ + Server getServer(); + + /** + * Sets the server instance that the event is posted on. The value provided + * to this method must be returned by subsequent calls to + * {@link #getServer()}. Do not call this method when handling the event. + * + * @param server the server dispatching the event or {@code null} to unbind + * any previously bound server + */ + void setServer(Server server); + + /** + * A default implementation of {@link ServerEvent}. This is not necessarily + * extended by server events. + */ + public static abstract class Default implements ServerEvent { + + private Server server; + + public Default(Server server) { + this.server = server; + } + + @Override + public Server getServer() { + return server; + } + + @Override + public void setServer(Server server) { + this.server = server; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java new file mode 100644 index 0000000..3071530 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java @@ -0,0 +1,192 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.management.load; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.PacketRevokeChunk; +import ru.windcorp.progressia.common.world.PacketSendChunk; +import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.test.TestWorldDiskIO; + +/** + * Chunk manager provides facilities to load, unload and generate chunks for a + * {@link Server} on demand. + */ +public class ChunkManager { + + private final LoadManager loadManager; + + public ChunkManager(LoadManager loadManager) { + this.loadManager = loadManager; + } + + /** + * @return the loadManager + */ + public LoadManager getLoadManager() { + return loadManager; + } + + /** + * @return the server + */ + public Server getServer() { + return getLoadManager().getServer(); + } + + /** + * Describes the result of an attempt to load a chunk. + */ + public static enum LoadResult { + /** + * A chunk has successfully been read from disk and is now loaded. + */ + LOADED_FROM_DISK, + + /** + * A chunk has successfully been generated and is now loaded. + */ + GENERATED, + + /** + * A chunk has already been loaded and so no action has been taken. + */ + ALREADY_LOADED, + + /** + * A chunk has not been loaded previously and the operation has failed + * to load it. It is not currently loaded. + */ + NOT_LOADED + } + + /** + * Loads or generates the chunk at the given location unless it is already + * loaded. The chunk is loaded after this method completes normally. + * + * @param chunkPos the position of the chunk + * @return one of {@link LoadResult#LOADED_FROM_DISK LOADED_FROM_DISK}, + * {@link LoadResult#GENERATED GENERATED} or + * {@link LoadResult#ALREADY_LOADED ALREADY_LOADED} + */ + public LoadResult loadOrGenerateChunk(Vec3i chunkPos) { + LoadResult loadResult = loadChunk(chunkPos); + + if (loadResult == LoadResult.NOT_LOADED || !getServer().getWorld().getChunk(chunkPos).isReady()) { + getServer().getWorld().generate(chunkPos); + return LoadResult.GENERATED; + } else { + return loadResult; + } + } + + /** + * Attempts to load the chunk from disk unless it is already loaded. If the + * chunk is not currently loaded and it is not available on the disk this + * method does nothing. + * + * @param chunkPos the position of the chunk + * @return one of {@link LoadResult#LOADED_FROM_DISK LOADED_FROM_DISK}, + * {@link LoadResult#NOT_LOADED NOT_LOADED} or + * {@link LoadResult#ALREADY_LOADED ALREADY_LOADED} + */ + public LoadResult loadChunk(Vec3i chunkPos) { + if (isChunkLoaded(chunkPos)) { + return LoadResult.ALREADY_LOADED; + } + + DefaultWorldData world = getServer().getWorld().getData(); + + DefaultChunkData chunk = TestWorldDiskIO.tryToLoad(chunkPos, world, getServer()); + if (chunk != null) { + world.addChunk(chunk); + return LoadResult.LOADED_FROM_DISK; + } else { + return LoadResult.NOT_LOADED; + } + } + + /** + * Unloads the chunk and saves it to disk if the chunk is loaded, otherwise + * does nothing. + * + * @param chunkPos the position of the chunk + * @return {@code true} iff the chunk had been loaded and was unloaded by + * this method + */ + public boolean unloadChunk(Vec3i chunkPos) { + DefaultWorldData world = getServer().getWorld().getData(); + DefaultChunkData chunk = world.getChunk(chunkPos); + + if (chunk == null) { + return false; + } + + world.removeChunk(chunk); + TestWorldDiskIO.saveChunk(chunk, getServer()); + + return true; + } + + public void sendChunk(Player player, Vec3i chunkPos) { + DefaultChunkData chunk = getServer().getWorld().getData().getChunk(chunkPos); + + if (chunk == null) { + throw new IllegalStateException( + String.format( + "Chunk (%d; %d; %d) is not loaded, cannot send", + chunkPos.x, + chunkPos.y, + chunkPos.z + ) + ); + } + + PacketSendChunk packet = new PacketSendChunk(); + packet.set(chunk); + player.getClient().sendPacket(packet); + + getLoadManager().getVisionManager().getVision(player, true).getVisibleChunks().add(chunkPos); + } + + public void revokeChunk(Player player, Vec3i chunkPos) { + PacketRevokeChunk packet = new PacketRevokeChunk(); + packet.set(chunkPos); + player.getClient().sendPacket(packet); + + PlayerVision vision = getLoadManager().getVisionManager().getVision(player, false); + if (vision != null) { + vision.getVisibleChunks().remove(chunkPos); + } + } + + /** + * Checks whether or not the chunk at the specified location is loaded. A + * loaded chunk is accessible through the server's {@link DefaultWorldData} object. + * + * @param chunkPos the position of the chunk + * @return {@code true} iff the chunk is loaded + */ + public boolean isChunkLoaded(Vec3i chunkPos) { + return getServer().getWorld().isChunkLoaded(chunkPos); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java new file mode 100644 index 0000000..f720c7f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java @@ -0,0 +1,221 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.management.load; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.Units; +import ru.windcorp.progressia.common.world.generic.ChunkMap; +import ru.windcorp.progressia.common.world.generic.ChunkMaps; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.common.world.generic.ChunkSets; +import ru.windcorp.progressia.server.Server; + +/** + * Chunk request daemon gathers chunk requests from players (via {@link VisionManager}) and loads or unloads chunks appropriately. + */ +public class ChunkRequestDaemon { + + private static final float CHUNK_UNLOAD_DELAY = Units.get(5, "s"); + + private final ChunkManager chunkManager; + + private final ChunkSet loaded; + private final ChunkSet requested = ChunkSets.newHashSet(); + private final ChunkSet toLoad = ChunkSets.newHashSet(); + private final ChunkSet toGenerate = ChunkSets.newHashSet(); + private final ChunkSet toRequestUnload = ChunkSets.newHashSet(); + + private final Collection buffer = new ArrayList<>(); + + private static class ChunkUnloadRequest { + private final Vec3i chunkPos; + private final long unloadAt; + + public ChunkUnloadRequest(Vec3i chunkPos, long unloadAt) { + this.chunkPos = chunkPos; + this.unloadAt = unloadAt; + } + + /** + * @return the chunk position + */ + public Vec3i getChunkPos() { + return chunkPos; + } + + /** + * @return the moment when the chunks becomes eligible for unloading + */ + public long getUnloadAt() { + return unloadAt; + } + } + + private final ChunkMap unloadSchedule = ChunkMaps.newHashMap(); + + public ChunkRequestDaemon(ChunkManager chunkManager) { + this.chunkManager = chunkManager; + this.loaded = getServer().getWorld().getData().getLoadedChunks(); + } + + public void tick() { + synchronized (getServer().getWorld().getData()) { + synchronized (getServer().getPlayerManager().getMutex()) { + loadAndUnloadChunks(); + sendAndRevokeChunks(); + } + } + } + + private void loadAndUnloadChunks() { + gatherLoadRequests(); + updateLoadQueues(); + processLoadQueues(); + } + + private void gatherLoadRequests() { + requested.clear(); + + getChunkManager().getLoadManager().getVisionManager().forEachVision(vision -> { + vision.getRequestedChunks().clear(); + vision.getPlayer().requestChunksToLoad(vision.getRequestedChunks()::add); + requested.addAll(vision.getRequestedChunks()); + }); + } + + private void updateLoadQueues() { + toLoad.clear(); + toLoad.addAll(requested); + toLoad.removeAll(loaded); + + toRequestUnload.clear(); + toRequestUnload.addAll(loaded); + toRequestUnload.removeAll(requested); + } + + private void processLoadQueues() { + toRequestUnload.forEach(this::scheduleUnload); + toRequestUnload.clear(); + + toLoad.forEach(getChunkManager()::loadOrGenerateChunk); + toLoad.clear(); + + toGenerate.forEach(getChunkManager()::loadOrGenerateChunk); + toGenerate.clear(); + + unloadScheduledChunks(); + } + + private void scheduleUnload(Vec3i chunkPos) { + if (unloadSchedule.containsKey(chunkPos)) { + // Unload already requested, skip + return; + } + + long unloadAt = System.currentTimeMillis() + (long) (getUnloadDelay() * 1000); + Vec3i chunkPosCopy = new Vec3i(chunkPos); + + unloadSchedule.put(chunkPosCopy, new ChunkUnloadRequest(chunkPosCopy, unloadAt)); + } + + private void unloadScheduledChunks() { + long now = System.currentTimeMillis(); + + for (Iterator it = unloadSchedule.values().iterator(); it.hasNext();) { + ChunkUnloadRequest request = it.next(); + + if (request.getUnloadAt() < now) { + + it.remove(); + + if (requested.contains(request.getChunkPos())) { + continue; // do not unload chunks that became requested + } + + getChunkManager().unloadChunk(request.getChunkPos()); + } + } + } + + private void sendAndRevokeChunks() { + getChunkManager().getLoadManager().getVisionManager().forEachVision(vision -> { + revokeChunks(vision); + sendChunks(vision); + }); + } + + private void sendChunks(PlayerVision vision) { + vision.getRequestedChunks().forEachIn(getServer().getWorld(), chunk -> { + if (!chunk.isReady()) { + toGenerate.add(chunk); + return; + } + + if (vision.isChunkVisible(chunk.getPosition())) { + return; + } + + buffer.add(chunk.getPosition()); + }); + + if (buffer.isEmpty()) return; + for (Vec3i chunkPos : buffer) { + getChunkManager().sendChunk(vision.getPlayer(), chunkPos); + } + + buffer.clear(); + } + + private void revokeChunks(PlayerVision vision) { + vision.getVisibleChunks().forEach(chunkPos -> { + if (getChunkManager().isChunkLoaded(chunkPos) && vision.getRequestedChunks().contains(chunkPos)) + return; + buffer.add(new Vec3i(chunkPos)); + }); + + if (buffer.isEmpty()) return; + for (Vec3i chunkPos : buffer) { + getChunkManager().revokeChunk(vision.getPlayer(), chunkPos); + } + + buffer.clear(); + } + + /** + * @return the minimum amount of time a chunk will spend in the unload queue + */ + public float getUnloadDelay() { + return CHUNK_UNLOAD_DELAY; + } + + /** + * @return the manager + */ + public ChunkManager getChunkManager() { + return chunkManager; + } + + public Server getServer() { + return getChunkManager().getServer(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/EntityManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/EntityManager.java new file mode 100644 index 0000000..6aa3853 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/EntityManager.java @@ -0,0 +1,97 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.management.load; + +import gnu.trove.set.TLongSet; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.entity.PacketRevokeEntity; +import ru.windcorp.progressia.common.world.entity.PacketSendEntity; +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; + +public class EntityManager { + + private final LoadManager loadManager; + + private final TLongSet loaded; + + public EntityManager(LoadManager loadManager) { + this.loadManager = loadManager; + this.loaded = getServer().getWorld().getData().getLoadedEntities(); + } + + public void sendEntity(Player player, long entityId) { + PlayerVision vision = getLoadManager().getVisionManager().getVision(player, true); + if (!vision.getVisibleEntities().add(entityId)) { + return; + } + + EntityData entity = getServer().getWorld().getData().getEntity(entityId); + + if (entity == null) { + throw new IllegalStateException( + "Entity with entity ID " + EntityData.formatEntityId(entityId) + " is not loaded, cannot send" + ); + } + + PacketSendEntity packet = new PacketSendEntity(); + packet.set(entity); + player.getClient().sendPacket(packet); + } + + public void revokeEntity(Player player, long entityId) { + PlayerVision vision = getLoadManager().getVisionManager().getVision(player, false); + if (vision == null) { + return; + } + if (!vision.getVisibleEntities().remove(entityId)) { + return; + } + + PacketRevokeEntity packet = new PacketRevokeEntity(); + packet.set(entityId); + player.getClient().sendPacket(packet); + } + + public boolean isEntityVisible(Player player, long entityId) { + PlayerVision vision = getLoadManager().getVisionManager().getVision(player, false); + + if (vision == null) { + return false; + } + + return vision.isEntityVisible(entityId); + } + + public boolean isEntityLoaded(long entityId) { + return loaded.contains(entityId); + } + + /** + * @return the loadManager + */ + public LoadManager getLoadManager() { + return loadManager; + } + + public Server getServer() { + return getLoadManager().getServer(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/EntityRequestDaemon.java b/src/main/java/ru/windcorp/progressia/server/management/load/EntityRequestDaemon.java new file mode 100644 index 0000000..9605ffe --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/EntityRequestDaemon.java @@ -0,0 +1,121 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.management.load; + +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import gnu.trove.TLongCollection; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.list.array.TLongArrayList; +import gnu.trove.set.TLongSet; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.server.Server; + +public class EntityRequestDaemon { + + private final EntityManager entityManager; + + private final TLongCollection buffer = new TLongArrayList(); + + public EntityRequestDaemon(EntityManager entityManager) { + this.entityManager = entityManager; + } + + public void tick() { + synchronized (getServer().getWorld().getData()) { + synchronized (getServer().getPlayerManager().getMutex()) { + gatherRequests(); + revokeEntities(); + sendEntities(); + } + } + } + + private void gatherRequests() { + Vec3i v = Vectors.grab3i(); + + forEachVision(vision -> { + + TLongSet requestedEntities = vision.getRequestedEntities(); + requestedEntities.clear(); + + ChunkSet visibleChunks = vision.getVisibleChunks(); + getServer().getWorld().forEachEntity(entity -> { + if (visibleChunks.contains(entity.getChunkCoords(v))) { + requestedEntities.add(entity.getEntityId()); + } + }); + }); + + Vectors.release(v); + } + + private void sendEntities() { + forEachVision(vision -> { + for (TLongIterator it = vision.getRequestedEntities().iterator(); it.hasNext();) { + long entityId = it.next(); + if (getEntityManager().isEntityLoaded(entityId) && !vision.getVisibleEntities().contains(entityId)) { + buffer.add(entityId); + } + } + + if (buffer.isEmpty()) return; + for (TLongIterator it = buffer.iterator(); it.hasNext();) { + getEntityManager().sendEntity(vision.getPlayer(), it.next()); + } + + buffer.clear(); + }); + } + + private void revokeEntities() { + forEachVision(vision -> { + for (TLongIterator it = vision.getVisibleEntities().iterator(); it.hasNext();) { + long entityId = it.next(); + if (!getEntityManager().isEntityLoaded(entityId) || !vision.getRequestedEntities().contains(entityId)) { + buffer.add(entityId); + } + } + + if (buffer.isEmpty()) return; + for (TLongIterator it = buffer.iterator(); it.hasNext();) { + getEntityManager().revokeEntity(vision.getPlayer(), it.next()); + } + + buffer.clear(); + }); + } + + /** + * @return the entityManager + */ + public EntityManager getEntityManager() { + return entityManager; + } + + public Server getServer() { + return getEntityManager().getServer(); + } + + private void forEachVision(Consumer action) { + getEntityManager().getLoadManager().getVisionManager().forEachVision(action); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/LoadManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/LoadManager.java new file mode 100644 index 0000000..3670116 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/LoadManager.java @@ -0,0 +1,65 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.management.load; + +import ru.windcorp.progressia.server.Server; + +public class LoadManager { + + private final Server server; + private final ChunkManager chunkManager; + private final EntityManager entityManager; + private final VisionManager visionManager; + + public LoadManager(Server server) { + this.server = server; + + this.chunkManager = new ChunkManager(this); + this.entityManager = new EntityManager(this); + this.visionManager = new VisionManager(this); + } + + /** + * @return the chunkManager + */ + public ChunkManager getChunkManager() { + return chunkManager; + } + + /** + * @return the entityManager + */ + public EntityManager getEntityManager() { + return entityManager; + } + + /** + * @return the visionManager + */ + public VisionManager getVisionManager() { + return visionManager; + } + + /** + * @return the server + */ + public Server getServer() { + return server; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/PlayerVision.java b/src/main/java/ru/windcorp/progressia/server/management/load/PlayerVision.java new file mode 100644 index 0000000..bb8e474 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/PlayerVision.java @@ -0,0 +1,85 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.management.load; + +import glm.vec._3.i.Vec3i; +import gnu.trove.TCollections; +import gnu.trove.set.TLongSet; +import gnu.trove.set.hash.TLongHashSet; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.common.world.generic.ChunkSets; +import ru.windcorp.progressia.server.Player; + +public class PlayerVision { + + private final Player player; + + private final ChunkSet visibleChunks = ChunkSets.newSyncHashSet(); + private final ChunkSet requestedChunks = ChunkSets.newHashSet(); + + private final TLongSet visibleEntities = TCollections.synchronizedSet(new TLongHashSet()); + private final TLongSet requestedEntities = new TLongHashSet(); + + public PlayerVision(Player player) { + this.player = player; + } + + public boolean isChunkVisible(Vec3i chunkPos) { + return visibleChunks.contains(chunkPos); + } + + public boolean isEntityVisible(long entityId) { + return visibleEntities.contains(entityId); + } + + /** + * @return the requestedChunks + */ + public ChunkSet getRequestedChunks() { + return requestedChunks; + } + + /** + * @return the visibleChunks + */ + public ChunkSet getVisibleChunks() { + return visibleChunks; + } + + /** + * @return the requestedEntities + */ + public TLongSet getRequestedEntities() { + return requestedEntities; + } + + /** + * @return the visibleEntities + */ + public TLongSet getVisibleEntities() { + return visibleEntities; + } + + /** + * @return the player + */ + public Player getPlayer() { + return player; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java new file mode 100644 index 0000000..b4d2a93 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java @@ -0,0 +1,106 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.management.load; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import com.google.common.eventbus.Subscribe; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.common.world.generic.ChunkSets; +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.events.PlayerJoinedEvent; +import ru.windcorp.progressia.server.events.PlayerLeftEvent; + +public class VisionManager { + + private final LoadManager loadManager; + + private final Map visions = Collections.synchronizedMap(new HashMap<>()); + + public VisionManager(LoadManager loadManager) { + this.loadManager = loadManager; + getServer().subscribe(this); + } + + @Subscribe + private void onPlayerJoined(PlayerJoinedEvent event) { + getVision(event.getPlayer(), true); + } + + @Subscribe + private void onPlayerLeft(PlayerLeftEvent event) { + visions.remove(event.getPlayer()); + } + + public PlayerVision getVision(Player player, boolean createIfMissing) { + if (createIfMissing) { + return visions.computeIfAbsent(player, PlayerVision::new); + } else { + return visions.get(player); + } + } + + public void forEachVision(Consumer action) { + visions.values().forEach(action); + } + + public boolean isChunkVisible(Vec3i chunkPos, Player player) { + PlayerVision vision = getVision(player, false); + + if (vision == null) { + return false; + } + + return vision.isChunkVisible(chunkPos); + } + + public ChunkSet getVisibleChunks(Player player) { + PlayerVision vision = getVision(player, false); + + if (vision == null) { + return ChunkSets.empty(); + } + + return vision.getVisibleChunks(); + } + + /** + * @return the loadManager + */ + public LoadManager getLoadManager() { + return loadManager; + } + + /** + * @return the chunkManager + */ + public ChunkManager getChunkManager() { + return getLoadManager().getChunkManager(); + } + + public Server getServer() { + return getLoadManager().getServer(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java index 37685d2..a9c3392 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java @@ -15,185 +15,27 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package ru.windcorp.progressia.server.world; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.function.BiConsumer; - import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericChunk; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileReference; -import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; -import ru.windcorp.progressia.server.world.block.TickableBlock; -import ru.windcorp.progressia.server.world.tasks.TickChunk; -import ru.windcorp.progressia.server.world.ticking.TickingPolicy; -import ru.windcorp.progressia.server.world.tile.TickableTile; -import ru.windcorp.progressia.server.world.tile.TileLogic; -import ru.windcorp.progressia.server.world.tile.TileLogicRegistry; -import ru.windcorp.progressia.server.world.tile.TileLogicStack; +import ru.windcorp.progressia.common.world.rels.BlockFace; -public class ChunkLogic implements GenericChunk { +public interface ChunkLogic extends ChunkLogicRO { - private final WorldLogic world; - private final ChunkData data; + /* + * Override return type + */ + + @Override + ChunkData getData(); - private final Collection tickingBlocks = new ArrayList<>(); - private final Collection tickingTiles = new ArrayList<>(); - - private final TickChunk tickTask = new TickChunk(this); - - private final Map tileLogicLists = Collections - .synchronizedMap(new WeakHashMap<>()); - - public ChunkLogic(WorldLogic world, ChunkData data) { - this.world = world; - this.data = data; - - tmp_generateTickLists(); + @Override + default TileLogicStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { + return (TileLogicStack) ChunkLogicRO.super.getTilesOrNull(blockInChunk, face); } @Override - public Vec3i getPosition() { - return getData().getPosition(); - } - - @Override - public BlockLogic getBlock(Vec3i blockInChunk) { - return BlockLogicRegistry.getInstance().get( - getData().getBlock(blockInChunk).getId() - ); - } - - @Override - public TileLogicStack getTiles(Vec3i blockInChunk, BlockFace face) { - return getTileStackWrapper(getData().getTiles(blockInChunk, face)); - } - - @Override - public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { - return getData().hasTiles(blockInChunk, face); - } - - private TileLogicStack getTileStackWrapper(TileDataStack tileDataList) { - return tileLogicLists.computeIfAbsent( - tileDataList, - TileLogicStackImpl::new - ); - } - - public WorldLogic getWorld() { - return world; - } - - public ChunkData getData() { - return data; - } - - public boolean isReady() { - return getWorld().getGenerator().isChunkReady(getData().getGenerationHint()); - } - - public boolean hasTickingBlocks() { - return !tickingBlocks.isEmpty(); - } - - public boolean hasTickingTiles() { - return !tickingTiles.isEmpty(); - } - - public void forEachTickingBlock(BiConsumer action) { - tickingBlocks.forEach(blockInChunk -> { - action.accept(blockInChunk, getBlock(blockInChunk)); - }); - } - - public void forEachTickingTile(BiConsumer action) { - tickingTiles.forEach(ref -> { - action.accept( - ref, - TileLogicRegistry.getInstance().get(ref.get().getId()) - ); - }); - } - - public TickChunk getTickTask() { - return tickTask; - } - - private class TileLogicStackImpl extends TileLogicStack { - - private final TileDataStack parent; - - public TileLogicStackImpl(TileDataStack parent) { - this.parent = parent; - } - - @Override - public Vec3i getBlockInChunk(Vec3i output) { - return parent.getBlockInChunk(output); - } - - @Override - public ChunkLogic getChunk() { - return ChunkLogic.this; - } - - @Override - public BlockFace getFace() { - return parent.getFace(); - } - - @Override - public TileLogic get(int index) { - return TileLogicRegistry.getInstance().get(parent.get(index).getId()); - } - - @Override - public int size() { - return parent.size(); - } - - @Override - public TileDataStack getData() { - return parent; - } - - } - - private void tmp_generateTickLists() { - ChunkTickContext context = TickContextMutable.start().withChunk(this).build(); - - context.forEachBlock(bctxt -> { - BlockLogic block = bctxt.getBlock(); - - if (!(block instanceof TickableBlock)) - return; - - if (((TickableBlock) block).getTickingPolicy(bctxt) == TickingPolicy.REGULAR) { - tickingBlocks.add(Coordinates.convertInWorldToInChunk(bctxt.getBlockInWorld(), null)); - } - - bctxt.forEachFace(fctxt -> fctxt.forEachTile(tctxt -> { - TileLogic tile = tctxt.getTile(); - - if (!(tile instanceof TickableTile)) - return; - - if (((TickableTile) tile).getTickingPolicy(tctxt) == TickingPolicy.REGULAR) { - tickingTiles.add(tctxt.getReference()); - } - })); - }); - } + TileLogicStack getTiles(Vec3i blockInChunk, BlockFace face); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogicRO.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogicRO.java new file mode 100644 index 0000000..5631027 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogicRO.java @@ -0,0 +1,15 @@ +package ru.windcorp.progressia.server.world; + +import ru.windcorp.progressia.common.world.ChunkDataRO; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface ChunkLogicRO + extends ChunkGenericRO { + + ChunkDataRO getData(); + + boolean isReady(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java deleted file mode 100644 index 5eed263..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.server.world; - -import java.util.function.Consumer; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.server.world.block.BlockTickContext; - -public interface ChunkTickContext extends TickContext { - - Vec3i getChunk(); - - default ChunkLogic getChunkLogic() { - return getWorld().getChunk(getChunk()); - } - - default ChunkData getChunkData() { - ChunkLogic chunkLogic = getChunkLogic(); - return chunkLogic == null ? null : chunkLogic.getData(); - } - - default void forEachBlock(Consumer action) { - TickContextMutable context = TickContextMutable.uninitialized(); - - getChunkData().forEachBlock(blockInChunk -> { - context.rebuild().withServer(getServer()).withChunk(getChunk()).withBlockInChunk(blockInChunk).build(); - action.accept(context); - }); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java new file mode 100644 index 0000000..d18ff11 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java @@ -0,0 +1,269 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.function.BiConsumer; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; +import ru.windcorp.progressia.server.world.block.TickableBlock; +import ru.windcorp.progressia.server.world.context.ServerBlockContextRO; +import ru.windcorp.progressia.server.world.context.ServerContexts; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; +import ru.windcorp.progressia.server.world.context.ServerWorldContextRO; +import ru.windcorp.progressia.server.world.tasks.TickChunk; +import ru.windcorp.progressia.server.world.ticking.TickingPolicy; +import ru.windcorp.progressia.server.world.tile.TickableTile; +import ru.windcorp.progressia.server.world.tile.TileLogic; +import ru.windcorp.progressia.server.world.tile.TileLogicRegistry; + +public class DefaultChunkLogic implements ChunkLogic { + + private final DefaultWorldLogic world; + private final DefaultChunkData data; + + private final Collection tickingBlocks = new ArrayList<>(); + private final Collection tickingTiles = new ArrayList<>(); + + private final TickChunk tickTask = new TickChunk(this); + + private final Map tileLogicLists = Collections + .synchronizedMap(new WeakHashMap<>()); + + public DefaultChunkLogic(DefaultWorldLogic world, DefaultChunkData data) { + this.world = world; + this.data = data; + + tmp_generateTickLists(); + } + + @Override + public Vec3i getPosition() { + return getData().getPosition(); + } + + @Override + public AbsFace getUp() { + return getData().getUp(); + } + + @Override + public BlockLogic getBlock(Vec3i blockInChunk) { + return BlockLogicRegistry.getInstance().get( + getData().getBlock(blockInChunk).getId() + ); + } + + @Override + public TileLogicStack getTiles(Vec3i blockInChunk, BlockFace face) { + return getTileStackWrapper(getData().getTiles(blockInChunk, face)); + } + + @Override + public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { + return getData().hasTiles(blockInChunk, face); + } + + private TileLogicStack getTileStackWrapper(TileDataStack tileDataList) { + return tileLogicLists.computeIfAbsent( + tileDataList, + TileLogicStackImpl::new + ); + } + + public DefaultWorldLogic getWorld() { + return world; + } + + @Override + public DefaultChunkData getData() { + return data; + } + + @Override + public boolean isReady() { + return getWorld().getGenerator().isChunkReady(getData().getGenerationHint()); + } + + public boolean hasTickingBlocks() { + return !tickingBlocks.isEmpty(); + } + + public boolean hasTickingTiles() { + return !tickingTiles.isEmpty(); + } + + public void forEachTickingBlock(BiConsumer action) { + tickingBlocks.forEach(blockInChunk -> { + action.accept(blockInChunk, getBlock(blockInChunk)); + }); + } + + public void forEachTickingTile(BiConsumer action) { + tickingTiles.forEach(ref -> { + action.accept( + ref, + TileLogicRegistry.getInstance().get(ref.get().getId()) + ); + }); + } + + public TickChunk getTickTask() { + return tickTask; + } + + private class TileLogicStackImpl extends AbstractList implements TileLogicStack { + private class TileLogicReferenceImpl implements TileLogicReference { + private final TileDataReference parent; + + public TileLogicReferenceImpl (TileDataReference parent) { + this.parent = parent; + } + + @Override + public TileDataReference getDataReference() { + return parent; + } + + @Override + public TileLogic get() { + return TileLogicRegistry.getInstance().get(parent.get().getId()); + } + + @Override + public int getIndex() { + return parent.getIndex(); + } + + @Override + public TileLogicStack getStack() { + return TileLogicStackImpl.this; + } + } + + private final TileDataStack parent; + + public TileLogicStackImpl(TileDataStack parent) { + this.parent = parent; + } + + @Override + public Vec3i getBlockInChunk(Vec3i output) { + return parent.getBlockInChunk(output); + } + + @Override + public DefaultChunkLogic getChunk() { + return DefaultChunkLogic.this; + } + + @Override + public RelFace getFace() { + return parent.getFace(); + } + + @Override + public TileLogicReference getReference(int index) { + return new TileLogicReferenceImpl(parent.getReference(index)); + } + + @Override + public int getIndexByTag(int tag) { + return parent.getIndexByTag(tag); + } + + @Override + public int getTagByIndex(int index) { + return parent.getTagByIndex(index); + } + + @Override + public TileLogic get(int index) { + return TileLogicRegistry.getInstance().get(parent.get(index).getId()); + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public TileDataStack getData() { + return parent; + } + + } + + private void tmp_generateTickLists() { + ServerWorldContextRO context = Server.getCurrentServer().createContext(getUp()); + + GenericChunks.forEachBiC(blockInChunk -> { + + ServerBlockContextRO blockContext = ServerContexts.pushAbs(context, this, blockInChunk); + BlockLogic block = getBlock(blockInChunk); + + if (!(block instanceof TickableBlock)) { + blockContext.pop(); + return; + } + + if (((TickableBlock) block).getTickingPolicy(blockContext) == TickingPolicy.REGULAR) { + tickingBlocks.add(blockInChunk.add_(0)); + } + + for (RelFace face : RelFace.getFaces()) { + TileLogicStack stack = getTilesOrNull(blockInChunk, face); + if (stack == null || stack.isEmpty()) continue; + + for (int i = 0; i < stack.size(); ++i) { + ServerTileContextRO tileContext = blockContext.push(context.toContext(face.resolve(getUp())), i); + TileLogic tile = stack.get(i); + + if (tile instanceof TickableTile) { + TickingPolicy policy = ((TickableTile) tile).getTickingPolicy(tileContext); + if (policy == TickingPolicy.REGULAR) { + tickingTiles.add(stack.getData().getReference(i)); + } + } + + tileContext.pop(); + } + } + + blockContext.pop(); + + }); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java new file mode 100644 index 0000000..3e654b6 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java @@ -0,0 +1,148 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import glm.Glm; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.crash.CrashReports; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.ChunkDataListeners; +import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.common.world.WorldDataListener; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.generation.WorldGenerator; +import ru.windcorp.progressia.server.world.tasks.TickEntitiesTask; +import ru.windcorp.progressia.server.world.tasks.WorldAccessor; +import ru.windcorp.progressia.server.world.ticking.Evaluation; + +public class DefaultWorldLogic implements WorldLogic { + + private final DefaultWorldData data; + private final Server server; + + private final WorldGenerator generator; + + private final Map chunks = new HashMap<>(); + + private final Evaluation tickEntitiesTask = new TickEntitiesTask(); + + public DefaultWorldLogic(DefaultWorldData data, Server server, WorldGenerator generator, WorldAccessor accessor) { + this.data = data; + this.server = server; + + this.generator = generator; + data.setGravityModel(getGenerator().getGravityModel()); + + data.addListener(new WorldDataListener() { + @Override + public void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { + chunks.put(chunk, new DefaultChunkLogic(DefaultWorldLogic.this, chunk)); + } + + @Override + public void beforeChunkUnloaded(DefaultWorldData world, DefaultChunkData chunk) { + chunks.remove(chunk); + } + }); + + data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(accessor))); + } + + @Override + public DefaultChunkLogic getChunk(Vec3i pos) { + return chunks.get(getData().getChunk(pos)); + } + + @Override + public Collection getChunks() { + return chunks.values(); + } + + @Override + public Collection getEntities() { + return getData().getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + return getData().getEntity(entityId); + } + + public Evaluation getTickEntitiesTask() { + return tickEntitiesTask; + } + + public Server getServer() { + return server; + } + + @Override + public DefaultWorldData getData() { + return data; + } + + public WorldGenerator getGenerator() { + return generator; + } + + public DefaultChunkData generate(Vec3i chunkPos) { + DefaultChunkData chunk = getGenerator().generate(chunkPos); + + if (!Glm.equals(chunkPos, chunk.getPosition())) { + throw CrashReports.report(null, "Generator %s has generated a chunk at (%d; %d; %d) when requested to generate a chunk at (%d; %d; %d)", + getGenerator(), + chunk.getX(), chunk.getY(), chunk.getZ(), + chunkPos.x, chunkPos.y, chunkPos.z + ); + } + + if (getData().getChunk(chunk.getPosition()) != chunk) { + if (isChunkLoaded(chunkPos)) { + throw CrashReports.report(null, "Generator %s has returned a chunk different to the chunk that is located at (%d; %d; %d)", + getGenerator(), + chunkPos.x, chunkPos.y, chunkPos.z + ); + } else { + throw CrashReports.report(null, "Generator %s has returned a chunk that is not loaded when requested to generate a chunk at (%d; %d; %d)", + getGenerator(), + chunkPos.x, chunkPos.y, chunkPos.z + ); + } + } + + if (!getChunk(chunk).isReady()) { + throw CrashReports.report(null, "Generator %s has returned a chunk that is not ready when requested to generate a chunk at (%d; %d; %d)", + getGenerator(), + chunkPos.x, chunkPos.y, chunkPos.z + ); + } + + return chunk; + } + + public DefaultChunkLogic getChunk(DefaultChunkData chunkData) { + return chunks.get(chunkData); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java index 22d106e..9e21c63 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java @@ -15,28 +15,36 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.world.block.BlockFace; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.block.BlockTickContext; import ru.windcorp.progressia.server.world.block.TickableBlock; import ru.windcorp.progressia.server.world.block.UpdateableBlock; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerContexts; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileStackContext; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; import ru.windcorp.progressia.server.world.entity.EntityLogic; import ru.windcorp.progressia.server.world.entity.EntityLogicRegistry; import ru.windcorp.progressia.server.world.tile.TickableTile; import ru.windcorp.progressia.server.world.tile.TileLogic; -import ru.windcorp.progressia.server.world.tile.TileTickContext; import ru.windcorp.progressia.server.world.tile.UpdateableTile; public class TickAndUpdateUtil { - public static void tickBlock(TickableBlock block, BlockTickContext context) { + public static void tickBlock(ServerBlockContext context) { + BlockLogic uncheckedBlock = context.logic().getBlock(); + if (!(uncheckedBlock instanceof BlockLogic)) { + return; + } + TickableBlock block = (TickableBlock) uncheckedBlock; try { block.tick(context); } catch (Exception e) { @@ -44,16 +52,21 @@ public class TickAndUpdateUtil { } } - public static void tickBlock(WorldLogic world, Vec3i blockInWorld) { - BlockLogic block = world.getBlock(blockInWorld); - if (!(block instanceof TickableBlock)) - return; // also checks nulls - - BlockTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).build(); - tickBlock((TickableBlock) block, tickContext); + public static void tickBlock(Server server, Vec3i blockInWorld) { + BlockLogic block = server.getWorld().getBlock(blockInWorld); + if (!(block instanceof TickableBlock)) { + return; + } + ServerBlockContext context = server.createContext(blockInWorld); + tickBlock(context); } - public static void tickTile(TickableTile tile, TileTickContext context) { + public static void tickTile(ServerTileContext context) { + TileLogic uncheckedTile = context.logic().getTile(); + if (!(uncheckedTile instanceof TickableTile)) { + return; + } + TickableTile tile = (TickableTile) uncheckedTile; try { tile.tick(context); } catch (Exception e) { @@ -61,72 +74,86 @@ public class TickAndUpdateUtil { } } - public static void tickTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { - TileLogic tile = world.getTile(blockInWorld, face, layer); - if (!(tile instanceof TickableTile)) + public static void tickTile(Server server, Vec3i blockInWorld, AbsFace face, int layer) { + TileLogic tile = server.getWorld().getTile(blockInWorld, face, layer); + if (!(tile instanceof TickableTile)) { return; - - TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face) - .withLayer(layer); - tickTile((TickableTile) tile, tickContext); + } + ServerTileContext context = ServerContexts.pushAbs(server.createContext(blockInWorld), blockInWorld, face) + .push(layer); + tickTile(context); } - public static void tickTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) { - TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build() - .forEachTile(context -> { - TileLogic tile = context.getTile(); - if (tile instanceof TickableTile) { - tickTile((TickableTile) tile, context); - } - }); + public static void tickTiles(Server server, Vec3i blockInWorld, AbsFace face) { + if (!server.getWorld().hasTiles(blockInWorld, face)) { + return; + } + + ServerTileStackContext context = ServerContexts.pushAbs(server.createContext(blockInWorld), blockInWorld, face); + for (int i = 0; i < context.getTileCount(); ++i) { + tickTile(context.push(i)); + context.pop(); + } } - public static void updateBlock(UpdateableBlock block, BlockTickContext context) { + public static void updateBlock(ServerBlockContext context) { + BlockLogic uncheckedBlock = context.logic().getBlock(); + if (!(uncheckedBlock instanceof BlockLogic)) { + return; + } + UpdateableBlock block = (UpdateableBlock) uncheckedBlock; try { block.update(context); } catch (Exception e) { - throw CrashReports.report(e, "Could not update block {}", block); + throw CrashReports.report(e, "Could not update block %s", block); } } - public static void updateBlock(WorldLogic world, Vec3i blockInWorld) { - BlockLogic block = world.getBlock(blockInWorld); - if (!(block instanceof UpdateableBlock)) - return; // also checks nulls - - BlockTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).build(); - updateBlock((UpdateableBlock) block, tickContext); + public static void updateBlock(Server server, Vec3i blockInWorld) { + BlockLogic block = server.getWorld().getBlock(blockInWorld); + if (!(block instanceof UpdateableBlock)) { + return; + } + ServerBlockContext context = server.createContext(blockInWorld); + updateBlock(context); } - public static void updateTile(UpdateableTile tile, TileTickContext context) { + public static void updateTile(ServerTileContext context) { + TileLogic uncheckedTile = context.logic().getTile(); + if (!(uncheckedTile instanceof UpdateableTile)) { + return; + } + UpdateableTile tile = (UpdateableTile) uncheckedTile; try { tile.update(context); } catch (Exception e) { - throw CrashReports.report(e, "Could not update tile {}", tile); + throw CrashReports.report(e, "Could not tick tile %s", tile); } } - public static void updateTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { - TileLogic tile = world.getTile(blockInWorld, face, layer); - if (!(tile instanceof UpdateableTile)) + public static void updateTile(Server server, Vec3i blockInWorld, AbsFace face, int layer) { + TileLogic tile = server.getWorld().getTile(blockInWorld, face, layer); + if (!(tile instanceof UpdateableTile)) { return; - - TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face) - .withLayer(layer); - updateTile((UpdateableTile) tile, tickContext); + } + ServerTileContext context = ServerContexts.pushAbs(server.createContext(blockInWorld), blockInWorld, face) + .push(layer); + updateTile(context); } - public static void updateTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) { - TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build() - .forEachTile(context -> { - TileLogic tile = context.getTile(); - if (tile instanceof UpdateableTile) { - updateTile((UpdateableTile) tile, context); - } - }); + public static void updateTiles(Server server, Vec3i blockInWorld, AbsFace face) { + if (!server.getWorld().hasTiles(blockInWorld, face)) { + return; + } + + ServerTileStackContext context = ServerContexts.pushAbs(server.createContext(blockInWorld), blockInWorld, face); + for (int i = 0; i < context.getTileCount(); ++i) { + updateTile(context.push(i)); + context.pop(); + } } - public static void tickEntity(EntityLogic logic, EntityData data, TickContext context) { + public static void tickEntity(EntityLogic logic, EntityData data, ServerWorldContext context) { try { logic.tick(data, context); } catch (Exception e) { @@ -138,7 +165,7 @@ public class TickAndUpdateUtil { tickEntity( EntityLogicRegistry.getInstance().get(data.getId()), data, - TickContextMutable.start().withServer(server).build() + server.createContext(data.getUpFace()) ); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java deleted file mode 100644 index 68185d9..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.server.world; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Function; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericTileStack; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileReference; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.block.BlockTickContext; -import ru.windcorp.progressia.server.world.tile.TSTickContext; -import ru.windcorp.progressia.server.world.tile.TileTickContext; - -public abstract class TickContextMutable implements BlockTickContext, TSTickContext, TileTickContext { - - private static enum Role { - NONE, WORLD, CHUNK, BLOCK, TILE_STACK, TILE; - } - - /* - * TickContextMutable interface - */ - - // Only TickContextMutable.Impl can extend; extend Impl if need be - private TickContextMutable() { - } - - public abstract Builder.Empty rebuild(); - - /* - * Static methods - */ - - public static TickContextMutable uninitialized() { - return new Impl(); - } - - public static Builder.Empty start() { - return uninitialized().rebuild(); - } - - public static Builder.World copyWorld(TickContext context) { - return start().withServer(context.getServer()); - } - - public static Builder.Chunk copyChunk(ChunkTickContext context) { - return start().withChunk(context.getChunkLogic()); - } - - public static Builder.Block copyBlock(BlockTickContext context) { - return copyWorld(context).withBlock(context.getBlockInWorld()); - } - - public static Builder.TileStack copyTS(TSTickContext context) { - return copyBlock(context).withFace(context.getFace()); - } - - public static TileTickContext copyTile(TileTickContext context) { - return copyTS(context).withLayer(context.getLayer()); - } - - /* - * Builder interfaces - */ - - public static interface Builder { - TickContextMutable build(); - - public static interface Empty /* does not extend Builder */ { - World withServer(Server server); - - default Builder.World withWorld(WorldLogic world) { - Objects.requireNonNull(world, "world"); - return withServer(world.getServer()); - } - - default Builder.Chunk withChunk(ChunkLogic chunk) { - Objects.requireNonNull(chunk, "chunk"); - return withWorld(chunk.getWorld()).withChunk(chunk.getPosition()); - } - } - - public static interface World extends Builder { - Chunk withChunk(Vec3i chunk); - - Block withBlock(Vec3i blockInWorld); - - TileStack withTS(GenericTileStack tileStack); - - default Builder.Chunk withChunk(ChunkData chunk) { - Objects.requireNonNull(chunk, "chunk"); - return withChunk(chunk.getPosition()); - } - - default TileTickContext withTile(TileReference ref) { - Objects.requireNonNull(ref, "ref"); - return withTS(ref.getStack()).withLayer(ref.getIndex()); - } - } - - public static interface Chunk extends Builder { - Builder.Block withBlockInChunk(Vec3i blockInChunk); - } - - public static interface Block extends Builder { - Builder.TileStack withFace(BlockFace face); - } - - public static interface TileStack extends Builder { - TickContextMutable withLayer(int layer); - } - } - - /* - * Impl - */ - - public static class Impl - extends TickContextMutable - implements Builder.Empty, Builder.World, Builder.Chunk, Builder.Block, Builder.TileStack { - - protected Impl() { - } - - protected Server server; - protected final Vec3i chunk = new Vec3i(); - protected final Vec3i blockInWorld = new Vec3i(); - protected BlockFace face; - protected int layer; - - protected Role role = Role.NONE; - protected boolean isBeingBuilt = false; - - /** - * Updated lazily - */ - protected final Vec3i blockInChunk = new Vec3i(); - - /* - * TickContextMutable - */ - - @Override - public Server getServer() { - checkContextState(Role.WORLD); - return this.server; - } - - @Override - public float getTickLength() { - checkContextState(Role.WORLD); - return (float) this.server.getTickLength(); - } - - @Override - public Vec3i getChunk() { - checkContextState(Role.CHUNK); - return this.chunk; - } - - @Override - public Vec3i getBlockInWorld() { - checkContextState(Role.BLOCK); - return this.blockInWorld; - } - - @Override - public BlockFace getFace() { - checkContextState(Role.TILE_STACK); - return this.face; - } - - @Override - public int getLayer() { - checkContextState(Role.TILE); - return this.layer; - } - - @Override - public Builder.Empty rebuild() { - this.role = Role.NONE; - this.isBeingBuilt = true; - - this.server = null; - this.chunk.set(0); - this.blockInWorld.set(0); - this.face = null; - this.layer = -1; - - return this; - } - - /* - * Builder - * memo: do NOT use Context getters, they throw ISEs - */ - - @Override - public TickContextMutable build() { - checkBuilderState(null); - this.isBeingBuilt = false; - return this; - } - - @Override - public World withServer(Server server) { - Objects.requireNonNull(server, "server"); - checkBuilderState(Role.NONE); - this.server = server; - this.role = Role.WORLD; - return this; - } - - @Override - public Chunk withChunk(Vec3i chunk) { - Objects.requireNonNull(chunk, "chunk"); - checkBuilderState(Role.WORLD); - - this.chunk.set(chunk.x, chunk.y, chunk.z); - - this.role = Role.CHUNK; - return this; - } - - @Override - public Block withBlock(Vec3i blockInWorld) { - Objects.requireNonNull(blockInWorld, "blockInWorld"); - checkBuilderState(Role.WORLD); - - this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); - Coordinates.convertInWorldToChunk(blockInWorld, this.chunk); - - this.role = Role.BLOCK; - return this; - } - - @Override - public TileStack withTS(GenericTileStack tileStack) { - Objects.requireNonNull(tileStack, "tileStack"); - - return withBlock(tileStack.getBlockInWorld(this.blockInWorld)).withFace(tileStack.getFace()); - // ^^^^^^^^^^^^^^^^^ This is safe - } - - @Override - public Block withBlockInChunk(Vec3i blockInChunk) { - Objects.requireNonNull(blockInChunk, "blockInChunk"); - checkBuilderState(Role.CHUNK); - - Coordinates.getInWorld(this.chunk, blockInChunk, this.blockInWorld); - - this.role = Role.BLOCK; - return this; - } - - @Override - public TileStack withFace(BlockFace face) { - Objects.requireNonNull(face, "face"); - checkBuilderState(Role.BLOCK); - - this.face = face; - - this.role = Role.TILE_STACK; - return this; - } - - @Override - public TickContextMutable withLayer(int layer) { - checkBuilderState(Role.TILE); - - this.layer = layer; - - this.role = Role.TILE; - return build(); - } - - /* - * Optimization - */ - - @Override - public Vec3i getBlockInChunk() { - return Coordinates.convertInWorldToInChunk(getBlockInWorld(), this.blockInChunk); - } - - @Override - public void forEachBlock(Consumer action) { - checkContextState(Role.CHUNK); - - Vec3i v = this.blockInWorld; - - int previousX = v.x; - int previousY = v.y; - int previousZ = v.z; - Role previousRole = this.role; - - this.role = Role.BLOCK; - - final int minX = Coordinates.getInWorld(chunk.x, 0); - final int minY = Coordinates.getInWorld(chunk.y, 0); - final int minZ = Coordinates.getInWorld(chunk.z, 0); - final int size = ChunkData.BLOCKS_PER_CHUNK; - - for (v.x = minX; v.x < minX + size; ++v.x) { - for (v.y = minY; v.y < minY + size; ++v.y) { - for (v.z = minZ; v.z < minZ + size; ++v.z) { - action.accept(this); - } - } - } - - this.role = previousRole; - blockInWorld.set(previousX, previousY, previousZ); - } - - @Override - public void forEachFace(Consumer action) { - checkContextState(Role.BLOCK); - BlockFace previousFace = this.face; - Role previousRole = this.role; - - this.role = Role.TILE_STACK; - for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { - this.face = BlockFace.getFaces().get(i); - action.accept(this); - } - - this.role = previousRole; - this.face = previousFace; - } - - @Override - public R evalNeighbor(Vec3i direction, Function action) { - this.blockInWorld.add(direction); - R result = action.apply(this); - this.blockInWorld.sub(direction); - - return result; - } - - @Override - public void forNeighbor(Vec3i direction, Consumer action) { - this.blockInWorld.add(direction); - action.accept(this); - this.blockInWorld.sub(direction); - } - - @Override - public boolean forEachTile(Consumer action) { - checkContextState(Role.TILE_STACK); - int previousLayer = this.layer; - Role previousRole = this.role; - - this.role = Role.TILE; - TileDataStack stack = getTDSOrNull(); - if (stack == null || stack.isEmpty()) - return false; - - for (this.layer = 0; this.layer < stack.size(); ++this.layer) { - action.accept(this); - } - - this.role = previousRole; - this.layer = previousLayer; - return true; - } - - @Override - public R evalComplementary(Function action) { - Objects.requireNonNull(action, "action"); - checkContextState(Role.TILE_STACK); - - this.blockInWorld.add(this.face.getVector()); - this.face = this.face.getCounter(); - R result = action.apply(this); - this.face = this.face.getCounter(); - this.blockInWorld.sub(this.face.getVector()); - - return result; - } - - @Override - public void forComplementary(Consumer action) { - Objects.requireNonNull(action, "action"); - checkContextState(Role.TILE_STACK); - - this.blockInWorld.add(this.face.getVector()); - this.face = this.face.getCounter(); - action.accept(this); - this.face = this.face.getCounter(); - this.blockInWorld.sub(this.face.getVector()); - } - - /* - * Misc - */ - - protected void checkContextState(Role requiredRole) { - if (isBeingBuilt) { - throw new IllegalStateException("This context is still being built"); - } - - if ((role == null) || (requiredRole.compareTo(role) > 0)) { - throw new IllegalStateException( - "This context is currently initialized as " + role + "; requested " + requiredRole - ); - } - } - - protected void checkBuilderState(Role requiredRole) { - if (!isBeingBuilt) { - throw new IllegalStateException("This context is already built"); - } - - if (requiredRole == null) { - if (role == Role.NONE) { - throw new IllegalStateException("This context is currently not initialized"); - } - } else { - if (role != requiredRole) { - throw new IllegalStateException( - "This context is currently initialized as " + role + "; requested " + requiredRole - ); - } - } - } - - @Override - public String toString() { - final String format; - - switch (this.role) { - case WORLD: - format = "TickContext"; - break; - case CHUNK: - format = "(%2$d; %3$d; %4$d)"; - break; - case BLOCK: - format = "(%5$d; %6$d; %7$d)"; - break; - case TILE_STACK: - format = "((%5$d; %6$d; %7$d); %8$6s)"; - break; - case TILE: - format = "((%5$d; %6$d; %7$d); %8$6s; %9$d)"; - break; - case NONE: - default: - format = "Uninitialized TickContextMutable"; - break; - } - - return String.format( - format, - this.chunk.x, - this.chunk.y, - this.chunk.z, - this.blockInWorld.x, - this.blockInWorld.y, - this.blockInWorld.z, - this.face, - this.layer - ); - } - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TileLogicReference.java b/src/main/java/ru/windcorp/progressia/server/world/TileLogicReference.java new file mode 100644 index 0000000..e56cffb --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/TileLogicReference.java @@ -0,0 +1,44 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world; + +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +/** + * A read-only {@link TileGenericReferenceRO TileReference} for a + * {@link TileData} that provides convenient read-write access to the matching + * {@link TileLogic} instance. + *

    + * For all methods other than {@link #get()}, {@link #getStack()} and + * {@link #getDataReference()}, + * logicRef.method() == logicRef.getDataReference().method(). + */ +public interface TileLogicReference + extends TileLogicReferenceRO { + + /* + * Override return type + */ + + @Override + TileDataReference getDataReference(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TileLogicReferenceRO.java b/src/main/java/ru/windcorp/progressia/server/world/TileLogicReferenceRO.java new file mode 100644 index 0000000..2a92764 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/TileLogicReferenceRO.java @@ -0,0 +1,82 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world; + +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.common.world.TileDataReferenceRO; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +/** + * A {@link TileGenericReferenceRO TileReference} for a {@link TileData} that + * provides convenient access to the matching {@link TileLogic} instance. + *

    + * For all methods other than {@link #get()}, {@link #getStack()} and + * {@link #getDataReference()}, + * logicRef.method() == logicRef.getDataReference().method(). + */ +public interface TileLogicReferenceRO + extends TileGenericReferenceRO { + + /** + * Returns a reference to the {@link TileData} that this object references. + * + * @return a {@link TileDataReference} equivalent to this object + */ + TileDataReferenceRO getDataReference(); + + /** + * Returns the {@link TileData} that is referenced by this object, or + * {@code null} if the tile does not exist. + * + * @return the relevant {@link TileData} + */ + default TileData getData() { + return getDataReference().get(); + } + + /** + * {@inheritDoc} + * + * @see #getData() + */ + @Override + TileLogic get(); + + /* + * Refer to #getDataReference() by default + */ + + @Override + default int getIndex() { + return getDataReference().getIndex(); + } + + @Override + default int getTag() { + return getDataReference().getTag(); + } + + @Override + default boolean isValid() { + return getDataReference().isValid(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TileLogicStack.java b/src/main/java/ru/windcorp/progressia/server/world/TileLogicStack.java new file mode 100644 index 0000000..3b8ef2f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/TileLogicStack.java @@ -0,0 +1,37 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world; + +import ru.windcorp.progressia.common.world.TileDataStack; + +public interface TileLogicStack extends TileLogicStackRO { + + /* + * Override return types + */ + + @Override + TileDataStack getData(); + + @Override + ChunkLogic getChunk(); + + @Override + TileLogicReference getReference(int index); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TileLogicStackRO.java b/src/main/java/ru/windcorp/progressia/server/world/TileLogicStackRO.java new file mode 100644 index 0000000..3561663 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/TileLogicStackRO.java @@ -0,0 +1,31 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world; + +import ru.windcorp.progressia.common.world.TileDataStackRO; +import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface TileLogicStackRO + extends TileGenericStackRO { + + public abstract TileDataStackRO getData(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java index 511170e..8175937 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java +++ b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java @@ -15,45 +15,45 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.tasks.WorldAccessor; public class UpdateTriggerer implements ChunkDataListener { - private final Server server; + private final WorldAccessor worldAccessor; - public UpdateTriggerer(Server server) { - this.server = server; + public UpdateTriggerer(WorldAccessor worldAccessor) { + this.worldAccessor = worldAccessor; } @Override public void onChunkBlockChanged( - ChunkData chunk, + DefaultChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current ) { - server.getWorldAccessor().triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null)); + worldAccessor.triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null)); } @Override public void onChunkTilesChanged( - ChunkData chunk, + DefaultChunkData chunk, Vec3i blockInChunk, - BlockFace face, + RelFace face, TileData tile, boolean wasAdded ) { - server.getWorldAccessor().triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null), face); + worldAccessor.triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null), face); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index 93a1028..f0cdb0a 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -15,105 +15,42 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package ru.windcorp.progressia.server.world; import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.ChunkDataListeners; import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.WorldDataListener; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.GenericWorld; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.generation.WorldGenerator; -import ru.windcorp.progressia.server.world.tasks.TickEntitiesTask; -import ru.windcorp.progressia.server.world.ticking.Evaluation; -import ru.windcorp.progressia.server.world.tile.TileLogic; -import ru.windcorp.progressia.server.world.tile.TileLogicStack; +import ru.windcorp.progressia.common.world.rels.BlockFace; -public class WorldLogic - implements GenericWorld { +public interface WorldLogic extends WorldLogicRO { - private final WorldData data; - private final Server server; + /* + * Override return types + */ + + @Override + WorldData getData(); - private final WorldGenerator generator; + @Override + ChunkLogic getChunk(Vec3i pos); - private final Map chunks = new HashMap<>(); + @Override + Collection getChunks(); - private final Evaluation tickEntitiesTask = new TickEntitiesTask(); - - public WorldLogic(WorldData data, Server server, Function worldGeneratorConstructor) { - this.data = data; - this.server = server; - this.generator = worldGeneratorConstructor.apply(this); - - data.addListener(new WorldDataListener() { - @Override - public void onChunkLoaded(WorldData world, ChunkData chunk) { - chunks.put(chunk, new ChunkLogic(WorldLogic.this, chunk)); - } - - @Override - public void beforeChunkUnloaded(WorldData world, ChunkData chunk) { - chunks.remove(chunk); - } - }); - - data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server))); + @Override + default ChunkLogic getChunkByBlock(Vec3i blockInWorld) { + return (ChunkLogic) WorldLogicRO.super.getChunkByBlock(blockInWorld); } @Override - public ChunkLogic getChunk(Vec3i pos) { - return chunks.get(getData().getChunk(pos)); + default TileLogicStack getTiles(Vec3i blockInWorld, BlockFace face) { + return (TileLogicStack) WorldLogicRO.super.getTiles(blockInWorld, face); } @Override - public Collection getChunks() { - return chunks.values(); - } - - @Override - public Collection getEntities() { - return getData().getEntities(); - } - - public Evaluation getTickEntitiesTask() { - return tickEntitiesTask; - } - - public Server getServer() { - return server; - } - - public WorldData getData() { - return data; - } - - public WorldGenerator getGenerator() { - return generator; - } - - public ChunkData generate(Vec3i chunkPos) { - return getGenerator().generate(chunkPos, getData()); - } - - public ChunkLogic getChunk(ChunkData chunkData) { - return chunks.get(chunkData); + default TileLogicStack getTilesOrNull(Vec3i blockInWorld, BlockFace face) { + return (TileLogicStack) WorldLogicRO.super.getTilesOrNull(blockInWorld, face); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogicRO.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogicRO.java new file mode 100644 index 0000000..7f98ef9 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogicRO.java @@ -0,0 +1,31 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world; + +import ru.windcorp.progressia.common.world.WorldDataRO; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.WorldGenericRO; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface WorldLogicRO + extends WorldGenericRO { + + WorldDataRO getData(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java index 794259f..f873093 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java @@ -15,28 +15,29 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.block; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.generic.BlockGeneric; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.ServerBlockContextRO; -public class BlockLogic extends Namespaced implements GenericBlock { +public class BlockLogic extends Namespaced implements BlockGeneric { public BlockLogic(String id) { super(id); } - public boolean isSolid(BlockTickContext context, BlockFace face) { + public boolean isSolid(ServerBlockContextRO context, RelFace face) { return isSolid(face); } - public boolean isSolid(BlockFace face) { + public boolean isSolid(RelFace face) { return true; } - public boolean isTransparent(BlockTickContext context) { + public boolean isTransparent(ServerBlockContextRO context) { return isTransparent(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogicRegistry.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogicRegistry.java index df18ff7..b50b02f 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogicRegistry.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogicRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.block; import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java deleted file mode 100644 index a305b9a..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.server.world.block; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Function; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.block.BlockRelation; -import ru.windcorp.progressia.server.world.ChunkTickContext; -import ru.windcorp.progressia.server.world.TickContextMutable; -import ru.windcorp.progressia.server.world.tile.TSTickContext; - -public interface BlockTickContext extends ChunkTickContext { - - /** - * Returns the current world coordinates. - * - * @return the world coordinates of the block being ticked - */ - Vec3i getBlockInWorld(); - - default Vec3i getBlockInChunk() { - return Coordinates.convertInWorldToInChunk(getBlockInWorld(), null); - } - - default BlockLogic getBlock() { - return getWorld().getBlock(getBlockInWorld()); - } - - default BlockData getBlockData() { - return getWorldData().getBlock(getBlockInWorld()); - } - - default void forEachFace(Consumer action) { - Objects.requireNonNull(action, "action"); - TickContextMutable context = TickContextMutable.uninitialized(); - - for (BlockFace face : BlockFace.getFaces()) { - context.rebuild().withServer(getServer()).withBlock(getBlockInWorld()).withFace(face).build(); - action.accept(context); - } - } - - default BlockTickContext getNeighbor(Vec3i direction) { - Objects.requireNonNull(direction, "direction"); - return TickContextMutable.copyWorld(this).withBlock(getBlockInWorld().add_(direction)).build(); - } - - default BlockTickContext getNeighbor(BlockRelation relation) { - Objects.requireNonNull(relation, "relation"); - return getNeighbor(relation.getVector()); - } - - default R evalNeighbor(Vec3i direction, Function action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(direction, "direction"); - return action.apply(getNeighbor(direction)); - } - - default R evalNeighbor(BlockRelation relation, Function action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(relation, "relation"); - return evalNeighbor(relation.getVector(), action); - } - - default void forNeighbor(Vec3i direction, Consumer action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(direction, "direction"); - evalNeighbor(direction, (Function) ctxt -> { - action.accept(ctxt); - return null; - }); - } - - default void forNeighbor(BlockRelation relation, Consumer action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(relation, "relation"); - forNeighbor(relation.getVector(), action); - } - - /* - * Convenience methods - changes - */ - - default void setThisBlock(BlockData block) { - getAccessor().setBlock(getBlockInWorld(), block); - } - - default void setThisBlock(String id) { - getAccessor().setBlock(getBlockInWorld(), id); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java b/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java index 56ba938..666cfd5 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java @@ -15,15 +15,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.block; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerBlockContextRO; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; public interface TickableBlock { - void tick(BlockTickContext context); + void tick(ServerBlockContext context); - TickingPolicy getTickingPolicy(BlockTickContext context); + TickingPolicy getTickingPolicy(ServerBlockContextRO context); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java b/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java index 1497c92..757e972 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java @@ -18,18 +18,10 @@ package ru.windcorp.progressia.server.world.block; -import org.apache.logging.log4j.LogManager; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; public interface UpdateableBlock { - default void update(BlockTickContext context) { - LogManager.getLogger().info( - "Updating block {} @ ({}; {}; {})", - context.getBlock(), - context.getBlockInWorld().x, - context.getBlockInWorld().y, - context.getBlockInWorld().z - ); - } + void update(ServerBlockContext context); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java new file mode 100644 index 0000000..e0b5c70 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java @@ -0,0 +1,87 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.BlockDataContext; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; + +public interface ServerBlockContext extends BlockDataContext, ServerWorldContext, ServerBlockContextRO { + + public interface Logic extends ServerBlockContextRO.Logic, ServerWorldContext.Logic { + + @Override + ServerBlockContext data(); + + @Override + default ServerBlockContext.Logic pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContext.Logic pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContext.Logic pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default ServerTileStackContext.Logic push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContext.Logic push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + + } + + @Override + ServerBlockContext.Logic logic(); + + @Override + default ServerBlockContext pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContext pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContext pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default ServerTileStackContext push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContext push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java new file mode 100644 index 0000000..1fdb90e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java @@ -0,0 +1,92 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.BlockDataContextRO; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface ServerBlockContextRO extends ServerWorldContextRO, BlockDataContextRO { + + public interface Logic + extends ServerWorldContextRO.Logic, BlockGenericContextRO { + + @Override + ServerBlockContextRO data(); + + @Override + default ServerBlockContextRO.Logic pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContextRO.Logic pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContextRO.Logic pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default ServerTileStackContextRO.Logic push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContextRO.Logic push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + + } + + @Override + ServerBlockContextRO.Logic logic(); + + @Override + default ServerBlockContextRO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContextRO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContextRO pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default ServerTileStackContextRO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContextRO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java new file mode 100644 index 0000000..052718f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java @@ -0,0 +1,82 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context; + +import java.util.Random; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.ServerState; + +/** + * A server-side {@link Context}. This context has a {@link Server} instance. + */ +public interface ServerContext extends Context { + + /** + * Gets the {@link Server} instance relevant to this context. This method + * should always be preferred to {@link ServerState#getInstance()} when + * possible. + * + * @return the server instance + */ + Server getServer(); + + /** + * Retrieves a context-appropriate source of randomness. This source should + * always be preferred to any other when possible. + * + * @return an intended {@link Random} instance + */ + Random getRandom(); + + /** + * Returns the duration of the last server tick. Server logic should assume + * that this much in-world time has passed. + * + * @return the length of the last server tick + */ + double getTickLength(); + + /** + * Adjusts the provided value according to tick length assuming the value + * scales linearly. The call {@code ctxt.adjustValue(x)} is equivalent to + * {@code ((float) ctxt.getTickLength()) * x}. + * + * @param valueForOneSecond the value to adjust, normalized to one second + * @return the value adjust to account for the actual tick length + * @see #getTickLength() + */ + default float adjustTime(float valueForOneSecond) { + return ((float) getTickLength()) * valueForOneSecond; + } + + /** + * Adjusts the provided value according to tick length assuming the value + * scales linearly. The call {@code ctxt.adjustValue(x)} is equivalent to + * {@code ctxt.getTickLength() * x}. + * + * @param valueForOneSecond the value to adjust, normalized to one second + * @return the value adjust to account for the actual tick length + * @see #getTickLength() + */ + default double adjustTime(double valueForOneSecond) { + return getTickLength() * valueForOneSecond; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerContexts.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerContexts.java new file mode 100644 index 0000000..b0cf996 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerContexts.java @@ -0,0 +1,141 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; + +public class ServerContexts { + + /* + * RW + */ + + public static ServerBlockContext pushAbs(ServerWorldContext context, Vec3i blockInWorld) { + Vec3i contextLocation = Vectors.grab3i(); + context.toContext(blockInWorld, contextLocation); + ServerBlockContext blockContext = context.push(contextLocation); + Vectors.release(contextLocation); + return blockContext; + } + + public static ServerBlockContext pushAbs(ServerWorldContext context, ChunkGenericRO chunk, Vec3i blockInChunk) { + Vec3i contextLocation = Vectors.grab3i(); + Coordinates.getInWorld(chunk.getPosition(), blockInChunk, contextLocation); + context.toContext(contextLocation, contextLocation); + ServerBlockContext blockContext = context.push(contextLocation); + Vectors.release(contextLocation); + return blockContext; + } + + public static ServerTileStackContext pushAbs(ServerWorldContext context, Vec3i blockInWorld, AbsFace face) { + Vec3i contextLocation = Vectors.grab3i(); + context.toContext(blockInWorld, contextLocation); + RelFace contextFace = context.toContext(face); + ServerTileStackContext tileStackContext = context.push(contextLocation, contextFace); + Vectors.release(contextLocation); + return tileStackContext; + } + + public static ServerTileStackContext pushAbs(ServerWorldContext context, ChunkGenericRO chunk, Vec3i blockInChunk, AbsFace face) { + Vec3i contextLocation = Vectors.grab3i(); + Coordinates.getInWorld(chunk.getPosition(), blockInChunk, contextLocation); + context.toContext(contextLocation, contextLocation); + RelFace contextFace = context.toContext(face); + ServerTileStackContext tileStackContext = context.push(contextLocation, contextFace); + Vectors.release(contextLocation); + return tileStackContext; + } + + public static ServerTileStackContext pushAbs(ServerBlockContext context, AbsFace face) { + return context.push(context.toContext(face)); + } + + public static ServerTileContext pushAbs(ServerWorldContext context, AbsFace up, TileGenericReferenceRO ref) { + Vec3i contextLocation = Vectors.grab3i(); + ref.getStack().getBlockInWorld(contextLocation); + context.toContext(contextLocation, contextLocation); + RelFace contextFace = context.toContext(ref.getStack().getFace().resolve(up)); + ServerTileContext tileContext = context.push(contextLocation, contextFace, ref.getIndex()); + Vectors.release(contextLocation); + return tileContext; + } + + /* + * RO + */ + + public static ServerBlockContextRO pushAbs(ServerWorldContextRO context, Vec3i blockInWorld) { + Vec3i contextLocation = Vectors.grab3i(); + context.toContext(blockInWorld, contextLocation); + ServerBlockContextRO blockContextRO = context.push(contextLocation); + Vectors.release(contextLocation); + return blockContextRO; + } + + public static ServerBlockContextRO pushAbs(ServerWorldContextRO context, ChunkGenericRO chunk, Vec3i blockInChunk) { + Vec3i contextLocation = Vectors.grab3i(); + Coordinates.getInWorld(chunk.getPosition(), blockInChunk, contextLocation); + context.toContext(contextLocation, contextLocation); + ServerBlockContextRO blockContextRO = context.push(contextLocation); + Vectors.release(contextLocation); + return blockContextRO; + } + + public static ServerTileStackContextRO pushAbs(ServerWorldContextRO context, Vec3i blockInWorld, AbsFace face) { + Vec3i contextLocation = Vectors.grab3i(); + context.toContext(blockInWorld, contextLocation); + RelFace contextFace = context.toContext(face); + ServerTileStackContextRO tileStackContextRO = context.push(contextLocation, contextFace); + Vectors.release(contextLocation); + return tileStackContextRO; + } + + public static ServerTileStackContextRO pushAbs(ServerWorldContextRO context, ChunkGenericRO chunk, Vec3i blockInChunk, AbsFace face) { + Vec3i contextLocation = Vectors.grab3i(); + Coordinates.getInWorld(chunk.getPosition(), blockInChunk, contextLocation); + context.toContext(contextLocation, contextLocation); + RelFace contextFace = context.toContext(face); + ServerTileStackContextRO tileStackContextRO = context.push(contextLocation, contextFace); + Vectors.release(contextLocation); + return tileStackContextRO; + } + + public static ServerTileStackContextRO pushAbs(ServerBlockContextRO context, AbsFace face) { + return context.push(context.toContext(face)); + } + + public static ServerTileContextRO pushAbs(ServerWorldContextRO context, AbsFace up, TileGenericReferenceRO ref) { + Vec3i contextLocation = Vectors.grab3i(); + ref.getStack().getBlockInWorld(contextLocation); + context.toContext(contextLocation, contextLocation); + RelFace contextFace = context.toContext(ref.getStack().getFace().resolve(up)); + ServerTileContextRO tileContextRO = context.push(contextLocation, contextFace, ref.getIndex()); + Vectors.release(contextLocation); + return tileContextRO; + } + + private ServerContexts() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java new file mode 100644 index 0000000..6850f43 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java @@ -0,0 +1,54 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context; + +import ru.windcorp.progressia.common.world.context.TileDataContext; + +public interface ServerTileContext extends TileDataContext, ServerTileStackContext, ServerTileContextRO { + + public interface Logic extends ServerTileContextRO.Logic, ServerTileStackContext.Logic { + + @Override + ServerTileContext data(); + + @Override + default ServerTileContext.Logic pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContext.Logic pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + + } + + @Override + ServerTileContext.Logic logic(); + + @Override + default ServerTileContext pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContext pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java new file mode 100644 index 0000000..18382bd --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java @@ -0,0 +1,59 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context; + +import ru.windcorp.progressia.common.world.context.TileDataContextRO; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.TileGenericContextRO; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface ServerTileContextRO extends ServerTileStackContextRO, TileDataContextRO { + + public interface Logic + extends ServerTileStackContextRO.Logic, TileGenericContextRO { + + @Override + ServerTileContextRO data(); + + @Override + default ServerTileContextRO.Logic pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContextRO.Logic pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + + } + + @Override + ServerTileContextRO.Logic logic(); + + @Override + default ServerTileContextRO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContextRO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java new file mode 100644 index 0000000..7454f26 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java @@ -0,0 +1,64 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context; + +import ru.windcorp.progressia.common.world.context.TileStackDataContext; + +public interface ServerTileStackContext extends TileStackDataContext, ServerBlockContext, ServerTileStackContextRO { + + public interface Logic extends ServerTileStackContextRO.Logic, ServerBlockContext.Logic { + + @Override + ServerTileStackContext data(); + + @Override + default ServerTileContext.Logic push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContext.Logic pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContext.Logic pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + + } + + @Override + ServerTileStackContext.Logic logic(); + + @Override + default ServerTileContext push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContext pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContext pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java new file mode 100644 index 0000000..ef2d476 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java @@ -0,0 +1,69 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context; + +import ru.windcorp.progressia.common.world.context.TileStackDataContextRO; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.TileStackGenericContextRO; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface ServerTileStackContextRO extends ServerBlockContextRO, TileStackDataContextRO { + + public interface Logic + extends ServerBlockContextRO.Logic, TileStackGenericContextRO { + + @Override + ServerTileStackContextRO data(); + + @Override + default ServerTileContextRO.Logic push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContextRO.Logic pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContextRO.Logic pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + + } + + @Override + ServerTileStackContextRO.Logic logic(); + + @Override + default ServerTileContextRO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContextRO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContextRO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java new file mode 100644 index 0000000..3de8038 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java @@ -0,0 +1,54 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.WorldDataContext; +import ru.windcorp.progressia.common.world.rels.RelFace; + +public interface ServerWorldContext extends WorldDataContext, ServerWorldContextRO { + + public interface Logic extends ServerWorldContextRO.Logic { + + @Override + ServerWorldContext data(); + + @Override + ServerBlockContext.Logic push(Vec3i location); + + @Override + ServerTileStackContext.Logic push(Vec3i location, RelFace face); + + @Override + ServerTileContext.Logic push(Vec3i location, RelFace face, int layer); + + } + + @Override + ServerWorldContext.Logic logic(); + + @Override + ServerBlockContext push(Vec3i location); + + @Override + ServerTileStackContext push(Vec3i location, RelFace face); + + @Override + ServerTileContext push(Vec3i location, RelFace face, int layer); + +} \ No newline at end of file diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java new file mode 100644 index 0000000..ff849c1 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java @@ -0,0 +1,53 @@ +package ru.windcorp.progressia.server.world.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.WorldDataContextRO; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface ServerWorldContextRO extends WorldDataContextRO, ServerContext { + + public interface Logic extends WorldGenericContextRO, ServerContext { + + /** + * Acquires the data view of this context. Use this method to + * conveniently access data content. The returned object is linked to + * this context and operates on the same data. + * + * @return a view of this context that returns data objects + */ + ServerWorldContextRO data(); + + @Override + ServerBlockContextRO.Logic push(Vec3i location); + + @Override + ServerTileStackContextRO.Logic push(Vec3i location, RelFace face); + + @Override + ServerTileContextRO.Logic push(Vec3i location, RelFace face, int layer); + + } + + /** + * Acquires the logic view of this context. Use this method to conveniently + * access logic content. The returned object is linked to this context and + * operates on the same data. + * + * @return a view of this context that returns appropriate logic objects + */ + ServerWorldContextRO.Logic logic(); + + @Override + ServerBlockContextRO push(Vec3i location); + + @Override + ServerTileStackContextRO push(Vec3i location, RelFace face); + + @Override + ServerTileContextRO push(Vec3i location, RelFace face, int layer); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContext.java new file mode 100644 index 0000000..afeadea --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContext.java @@ -0,0 +1,142 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context.impl; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.AbstractContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.WorldLogicRO; +import ru.windcorp.progressia.server.world.context.*; + +/** + * An implementation of the entire {@link ServerContext} tree. The objects of + * this class are designed to be highly reusable, including reusability in + * {@linkplain Context#subcontexting subcontexting}. Use this implementation + * when a {@link WorldLogic} (or a {@link WorldLogicRO}) instance requires a + * context wrapper. + *

    + * Use other unutilized instances of {@code ReusableServerContext} or + * {@link #empty()} static method to acquire a usable instance. + *

    + * {@code ReusableServerContext} asserts that is it {@linkplain #isReal() real} + * and {@linkplain #isImmediate() immediate}. It creates and provides an + * independent randomness source. The tick length is consulted with the server. + * Use wrappers to alter these properties. + *

    + * This class defines the outward-facing safe interface of the actual + * implementation located in {@link DefaultServerContextImpl}. The reasoning + * for creating a subclass is to allow a single instance to implement both + * {@linkplain DefaultServerContextBuilders builder interfaces} and the context + * interface without causing confusion around object states. + * + * @author javapony + */ +public abstract class DefaultServerContext extends AbstractContextRO + implements ServerTileContext { + + /** + * An RSC can conform to a variety of different {@link Context} interfaces. + * Each compliance mode is identified by a Role. + */ + public enum Role { + /** + * This object has not been configured yet. + */ + NONE, + /** + * This object conforms to {@link ServerWorldContext} or + * {@link ServerWorldContextRO}. + */ + WORLD, + /** + * This object conforms to {@link ServerBlockContext} or + * {@link ServerBlockContextRO}. + */ + LOCATION, + /** + * This object conforms to {@link ServerTileStackContext} or + * {@link ServerTileStackContextRO}. + */ + TILE_STACK, + /** + * This object conforms to {@link ServerTileContext} or + * {@link ServerTileContextRO}. + */ + TILE + } + + /** + * Do not extend ReusableServerContext directly. Use + * {@link DefaultServerContextImpl} if this is truly necessary. + */ + DefaultServerContext() { + // do nothing + } + + /** + * Resets this object to its uninitialized state and returns a builder to + * reinitialize it. + * + * @return a {@link DefaultServerContextBuilders.Empty} instance that may + * be used to reinitialize this object + * @throws IllegalStateException if active subcontexting is detected + */ + public abstract DefaultServerContextBuilders.Empty reuse() throws IllegalStateException; + + /** + * Returns the {@link Role} currently assumed by this object. + * + * @return the role + */ + public abstract Role getRole(); + + /** + * Instantiates a new {@link DefaultServerContext} using an appropriate + * implementation. + * + * @return a {@link DefaultServerContextBuilders.Empty} instance that can + * be used to initialize this object + */ + public static DefaultServerContextBuilders.Empty empty() { + return new DefaultServerContextImpl(); + } + + @Override + public DefaultServerContext push(Vec3i location) { + super.push(location); + return this; + } + + @Override + public DefaultServerContext push(Vec3i location, RelFace face) { + super.push(location, face); + return this; + } + + @Override + public DefaultServerContext push(Vec3i location, RelFace face, int layer) { + super.push(location, face, layer); + return this; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java new file mode 100644 index 0000000..cb182ce --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java @@ -0,0 +1,87 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context.impl; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; +import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.Server; + +public interface DefaultServerContextBuilders { + + DefaultServerContext build(); + + public interface Empty /* does not extend DSCB */ { + + WithWorld in(Server server, WorldData world); + + default WithWorld inRealWorldOf(Server server) { + return in(server, server.getWorld().getData()); + } + + } + + public interface WithWorld extends DefaultServerContextBuilders { + + WithLocation at(Vec3i location); + + default DefaultServerContext at(TileGenericReferenceRO reference) { + if (!reference.isValid()) { + throw new IllegalArgumentException("Reference " + reference + " is invalid"); + } + + TileGenericStackRO stack = reference.getStack(); + return at(stack.getBlockInWorld(null)).on(stack.getFace()).index(reference.getIndex()); + } + + } + + public interface WithLocation extends DefaultServerContextBuilders { + + WithTileStack on(RelFace side); + WithTileStack on(BlockFace side); + + default DefaultServerContext on(TileGenericReferenceRO reference) { + if (!reference.isValid()) { + throw new IllegalArgumentException("Reference " + reference + " is invalid"); + } + + TileGenericStackRO stack = reference.getStack(); + return on(stack.getFace()).index(reference.getIndex()); + } + + } + + public interface WithTileStack extends DefaultServerContextBuilders { + + DefaultServerContext index(int index); + + default DefaultServerContext index(TileGenericReferenceRO reference) { + if (!reference.isValid()) { + throw new IllegalArgumentException("Reference " + reference + " is invalid"); + } + + return index(reference.getIndex()); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java new file mode 100644 index 0000000..b4dfedc --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java @@ -0,0 +1,507 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context.impl; + +import java.util.Collection; +import java.util.Random; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.Server; + +class DefaultServerContextImpl extends DefaultServerContext + implements DefaultServerContextBuilders.Empty, DefaultServerContextBuilders.WithWorld, + DefaultServerContextBuilders.WithLocation, DefaultServerContextBuilders.WithTileStack { + + /* + * STATE MANAGEMENT & UTIL + */ + + public DefaultServerContextImpl() { + reuse(); + } + + /** + * The relevant {@link Server} instance. If this is {@code null}, the role + * is {@link Role#NONE}. + */ + protected Server server; + + /** + * The relevant {@link WorldData} instance. If this is {@code null}, the + * role is {@link Role#NONE}. + */ + protected WorldData world; + + /** + * The {@link Random} instance exposed with {@link #getRandom()}. + */ + protected final Random random = new Random(); + + /** + * Determines whether this object currently acts as a builder or a context. + */ + protected boolean isBuilder; + + /** + * Counts the instances of subcontexting that are currently active. This + * value increases by 1 when subcontexting begins and decreases by 1 when it + * ends. This is always 0 when the object is a builder. + */ + protected int subcontextDepth = 0; + + /** + * The Logic view returned by {@link #logic()}. + */ + protected final DefaultServerContextImpl.Logic logic = new DefaultServerContextLogic(this); + + /** + * Returns the Role currently assumed by this object. + * + * @return the role + */ + @Override + public Role getRole() { + if (server == null) + return Role.NONE; + if (frame == null) + return Role.WORLD; + if (frame.face == null) + return Role.LOCATION; + if (frame.layer == -1) + return Role.TILE_STACK; + return Role.TILE; + } + + /** + * Throws an {@link IllegalStateException} iff this object does not conform + * to the specified role. The object must not be a builder to pass the + * check. + * + * @param role the required role + * @return {@code true} (for convenience with {@code assert}) + * @throws IllegalStateException when the check fails + */ + public boolean requireContextRole(Role role) throws IllegalStateException { + + boolean ok = !isBuilder && getRole().compareTo(role) >= 0; + if (!ok) { + complainAboutIllegalState(role, false); + } + return true; + + } + + /** + * Throws an {@link IllegalStateException} iff this object does not conform + * to the specified role. The object must be a builder to pass the check. If + * {@code role} is {@code null}, any role except {@link Role#NONE} passes. + * + * @param role the required role or {@code null}, see above + * @return {@code true} (for convenience with {@code assert}) + * @throws IllegalStateException when the check fails + */ + public boolean requireBuilderRole(Role role) { + + boolean ok = isBuilder && role == null ? (getRole() != Role.NONE) : (getRole() == role); + if (!ok) { + complainAboutIllegalState(role, true); + } + return true; + + } + + private void complainAboutIllegalState(Role role, boolean builder) { + throw new IllegalStateException( + "Required " + (builder ? "builder for" : "context") + " " + role + + ", but I am currently " + this + ); + } + + @Override + public String toString() { + String result; + + switch (getRole()) { + case TILE: + result = String.format( + "ServerTileContext [x=%+4d, y=%+4d, z=%+4d, %s, index=%d]", + frame.location.x, + frame.location.y, + frame.location.z, + frame.face, + frame.layer + ); + break; + case TILE_STACK: + result = String + .format("ServerBlockFaceContext [x=%+4d, y=%+4d, z=%+4d, %s]", frame.location.x, frame.location.y, frame.location.z, frame.face); + break; + case LOCATION: + result = String.format("ServerBlockContext [x=%+4d, y=%+4d, z=%+4d]", frame.location.x, frame.location.y, frame.location.z); + break; + case WORLD: + result = "ServerWorldContext"; + break; + default: + result = "Uninitialized DefaultServerContext"; + break; + } + + if (isBuilder) { + result = "Builder for " + result; + } + + return result; + } + + /* + * RSC INTERFACE + */ + + @Override + public Empty reuse() { + + server = null; + world = null; + + while (isSubcontexting()) { + pop(); + } + + isBuilder = true; + + return this; + + } + + /* + * BUILDER INTERFACE + */ + + @Override + public DefaultServerContext build() { + assert requireBuilderRole(null); + isBuilder = false; + return this; + } + + /* + * Empty + */ + + @Override + public WithWorld in(Server server, WorldData world) { + requireBuilderRole(Role.NONE); + this.server = server; + this.world = world; + return this; + } + + /* + * WithWorld + */ + + @Override + public WithLocation at(Vec3i location) { + requireBuilderRole(Role.WORLD); + push(location); + return this; + } + + /* + * WithLocation + */ + + @Override + public WithTileStack on(RelFace side) { + requireBuilderRole(Role.LOCATION); + frame.face = side; + return this; + } + + @Override + public WithTileStack on(BlockFace side) { + requireBuilderRole(Role.LOCATION); + frame.face = side.relativize(world.getUp(frame.location)); + return this; + } + + /* + * WithTileStack + */ + + @Override + public DefaultServerContext index(int index) { + requireBuilderRole(Role.TILE_STACK); + frame.layer = index; + return build(); + } + + /* + * LOCATION GETTERS + */ + + @Override + public Server getServer() { + assert requireContextRole(Role.WORLD); + return server; + } + + @Override + public Vec3i getLocation() { + assert requireContextRole(Role.LOCATION); + return frame.location; + } + + @Override + public RelFace getFace() { + assert requireContextRole(Role.TILE_STACK); + return frame.face; + } + + @Override + public int getLayer() { + assert requireContextRole(Role.TILE); + return frame.layer; + } + + /* + * ABSOLUTE COORDINATE CONVERSIONS + * (or lack thereof) + */ + + @Override + public Vec3i toAbsolute(Vec3i contextLocation, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(contextLocation.x, contextLocation.y, contextLocation.z); + return output; + } + + @Override + public Vec3i toContext(Vec3i absoluteLocation, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(absoluteLocation.x, absoluteLocation.y, absoluteLocation.z); + return output; + } + + @Override + public AbsFace toAbsolute(RelFace contextFace) { + return contextFace.resolve(AbsFace.POS_Z); + } + + @Override + public RelFace toContext(AbsFace absoluteFace) { + return absoluteFace.relativize(AbsFace.POS_Z); + } + + /* + * RO CONTEXT INTERFACE + */ + + @Override + public boolean isReal() { + assert requireContextRole(Role.WORLD); + return true; + } + + @Override + public Random getRandom() { + assert requireContextRole(Role.WORLD); + return random; + } + + @Override + public double getTickLength() { + assert requireContextRole(Role.WORLD); + return server.getTickLength(); + } + + @Override + public BlockData getBlock(Vec3i location) { + assert requireContextRole(Role.WORLD); + return world.getBlock(location); + } + + @Override + public boolean isLocationLoaded(Vec3i location) { + assert requireContextRole(Role.WORLD); + return world.isLocationLoaded(location); + } + + @Override + public TileData getTile(Vec3i location, RelFace face, int layer) { + assert requireContextRole(Role.WORLD); + return world.getTile(location, face.resolve(AbsFace.POS_Z), layer); + } + + @Override + public boolean hasTile(Vec3i location, RelFace face, int layer) { + assert requireContextRole(Role.WORLD); + return world.hasTile(location, face.resolve(AbsFace.POS_Z), layer); + } + + @Override + public TileData getTileByTag(Vec3i location, RelFace face, int tag) { + assert requireContextRole(Role.WORLD); + TileDataStack stack = world.getTilesOrNull(location, face.resolve(AbsFace.POS_Z)); + if (stack == null) + return null; + int layer = stack.getIndexByTag(tag); + if (layer == -1) + return null; + return stack.get(layer); + } + + @Override + public boolean isTagValid(Vec3i location, RelFace face, int tag) { + assert requireContextRole(Role.WORLD); + TileDataStack stack = world.getTilesOrNull(location, face.resolve(AbsFace.POS_Z)); + if (stack == null) + return false; + return stack.getIndexByTag(tag) != -1; + } + + @Override + public int getTag() { + assert requireContextRole(Role.TILE); + TileDataStack stack = world.getTilesOrNull(frame.location, frame.face.resolve(AbsFace.POS_Z)); + if (stack == null) + return -1; + return stack.getTagByIndex(frame.layer); + } + + @Override + public int getTileCount(Vec3i location, RelFace face) { + assert requireContextRole(Role.TILE_STACK); + TileDataStack stack = world.getTilesOrNull(location, face.resolve(AbsFace.POS_Z)); + if (stack == null) + return 0; + return stack.size(); + } + + @Override + public Collection getEntities() { + assert requireContextRole(Role.WORLD); + return world.getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + assert requireContextRole(Role.WORLD); + return world.getEntity(entityId); + } + + @Override + public GravityModel getGravityModel() { + assert requireContextRole(Role.WORLD); + return world.getGravityModel(); + } + + @Override + public float getTime() { + assert requireContextRole(Role.WORLD); + return world.getTime(); + } + + /* + * RW CONTEXT INTERFACE + */ + + @Override + public boolean isImmediate() { + assert requireContextRole(Role.WORLD); + return true; + } + + @Override + public void setBlock(Vec3i blockInWorld, BlockData block) { + assert requireContextRole(Role.WORLD); + world.setBlock(blockInWorld, block, true); + } + + @Override + public void addTile(Vec3i location, RelFace face, TileData tile) { + assert requireContextRole(Role.WORLD); + world.getTiles(location, face.resolve(AbsFace.POS_Z)).addFarthest(tile); + } + + @Override + public void removeTile(Vec3i location, RelFace face, int tag) { + assert requireContextRole(Role.WORLD); + TileDataStack stack = world.getTilesOrNull(location, face.resolve(AbsFace.POS_Z)); + if (stack == null) + return; + int layer = stack.getIndexByTag(tag); + if (layer == -1) + return; + stack.remove(layer); + } + + @Override + public void addEntity(EntityData entity) { + assert requireContextRole(Role.WORLD); + world.addEntity(entity); + } + + @Override + public void removeEntity(long entityId) { + assert requireContextRole(Role.WORLD); + world.removeEntity(entityId); + } + + @Override + public void changeEntity(SE entity, StateChange change) { + assert requireContextRole(Role.WORLD); + world.changeEntity(entity, change); + } + + @Override + public void advanceTime(float change) { + assert requireContextRole(Role.WORLD); + world.advanceTime(change); + } + + /* + * ServerWorldContext.Logic STUFF + */ + + @Override + public Logic logic() { + assert requireContextRole(Role.WORLD); + return logic; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java new file mode 100644 index 0000000..d6bb661 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java @@ -0,0 +1,185 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context.impl; + +import java.util.Collection; +import java.util.Random; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.tile.TileLogic; +import ru.windcorp.progressia.server.world.tile.TileLogicRegistry; + +public class DefaultServerContextLogic implements ServerTileContext.Logic { + + private final ServerTileContext parent; + + public DefaultServerContextLogic(ServerTileContext parent) { + this.parent = parent; + } + + @Override + public ServerTileContext data() { + return parent; + } + + @Override + public Server getServer() { + return parent.getServer(); + } + + @Override + public Random getRandom() { + return parent.getRandom(); + } + + @Override + public BlockLogic getBlock(Vec3i location) { + BlockData data = parent.getBlock(location); + return data == null ? null : BlockLogicRegistry.getInstance().get(data.getId()); + } + + @Override + public boolean isLocationLoaded(Vec3i location) { + return parent.isLocationLoaded(location); + } + + @Override + public ServerTileContext.Logic push(Vec3i location) { + parent.push(location); + return this; + } + + @Override + public ServerTileContext.Logic push(Vec3i location, RelFace face) { + parent.push(location, face); + return this; + } + + @Override + public ServerTileContext.Logic push(Vec3i location, RelFace face, int layer) { + parent.push(location, face, layer); + return this; + } + + @Override + public Vec3i toAbsolute(Vec3i contextLocation, Vec3i output) { + return parent.toAbsolute(contextLocation, output); + } + + @Override + public Vec3i toContext(Vec3i absoluteLocation, Vec3i output) { + return parent.toContext(absoluteLocation, output); + } + + @Override + public AbsFace toAbsolute(RelFace contextFace) { + return parent.toAbsolute(contextFace); + } + + @Override + public RelFace toContext(AbsFace absoluteFace) { + return parent.toContext(absoluteFace); + } + + @Override + public double getTickLength() { + return parent.getTickLength(); + } + + @Override + public TileLogic getTile(Vec3i location, RelFace face, int layer) { + TileData data = parent.getTile(location, face, layer); + return data == null ? null : TileLogicRegistry.getInstance().get(data.getId()); + } + + @Override + public TileLogic getTileByTag(Vec3i location, RelFace face, int tag) { + TileData data = parent.getTileByTag(location, face, tag); + return data == null ? null : TileLogicRegistry.getInstance().get(data.getId()); + } + + @Override + public Vec3i getLocation() { + return parent.getLocation(); + } + + @Override + public boolean hasTile(Vec3i location, RelFace face, int layer) { + return parent.hasTile(location, face, layer); + } + + @Override + public boolean isTagValid(Vec3i location, RelFace face, int tag) { + return parent.isTagValid(location, face, tag); + } + + @Override + public boolean isReal() { + return parent.isReal(); + } + + @Override + public int getTileCount(Vec3i location, RelFace face) { + return parent.getTileCount(location, face); + } + + @Override + public Collection getEntities() { + return parent.getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + return parent.getEntity(entityId); + } + + @Override + public void pop() { + parent.pop(); + } + + @Override + public RelFace getFace() { + return parent.getFace(); + } + + @Override + public int getLayer() { + return parent.getLayer(); + } + + @Override + public int getTag() { + return parent.getTag(); + } + + @Override + public String toString() { + return parent + ".Logic"; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java new file mode 100644 index 0000000..80c5073 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java @@ -0,0 +1,243 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context.impl; + +import java.util.Collection; +import java.util.Random; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileStackContext; + +/** + * This is an implementation of the server context tree that delegates all calls + * to a provided instance of {@link ServerTileContext}. + */ +public abstract class FilterServerContext implements ServerTileContext { + + protected final ServerTileContext parent; + protected final DefaultServerContextLogic logic = new DefaultServerContextLogic(this); + + public FilterServerContext(ServerTileContext parent) { + this.parent = parent; + } + + public ServerTileContext getParent() { + return parent; + } + + @Override + public String toString() { + return getClass().getSimpleName() + " [" + parent + "]"; + } + + @Override + public int getLayer() { + return parent.getLayer(); + } + + @Override + public int getTag() { + return parent.getTag(); + } + + @Override + public RelFace getFace() { + return parent.getFace(); + } + + @Override + public Vec3i getLocation() { + return parent.getLocation(); + } + + @Override + public boolean isReal() { + return parent.isReal(); + } + + @Override + public void pop() { + parent.pop(); + } + + @Override + public boolean isImmediate() { + return parent.isImmediate(); + } + + @Override + public void setBlock(Vec3i location, BlockData block) { + parent.setBlock(location, block); + } + + @Override + public void addTile(Vec3i location, RelFace face, TileData tile) { + parent.addTile(location, face, tile); + } + + @Override + public void removeTile(Vec3i location, RelFace face, int tag) { + parent.removeTile(location, face, tag); + } + + @Override + public void addEntity(EntityData entity) { + parent.addEntity(entity); + } + + @Override + public void removeEntity(long entityId) { + parent.removeEntity(entityId); + } + + @Override + public void changeEntity(SE entity, StateChange change) { + parent.changeEntity(entity, change); + } + + @Override + public void advanceTime(float change) { + parent.advanceTime(change); + } + + @Override + public float getTime() { + return parent.getTime(); + } + + @Override + public GravityModel getGravityModel() { + return parent.getGravityModel(); + } + + @Override + public BlockData getBlock(Vec3i location) { + return parent.getBlock(location); + } + + @Override + public boolean isLocationLoaded(Vec3i location) { + return parent.isLocationLoaded(location); + } + + @Override + public TileData getTile(Vec3i location, RelFace face, int layer) { + return parent.getTile(location, face, layer); + } + + @Override + public TileData getTileByTag(Vec3i location, RelFace face, int tag) { + return parent.getTileByTag(location, face, tag); + } + + @Override + public boolean hasTile(Vec3i location, RelFace face, int layer) { + return parent.hasTile(location, face, layer); + } + + @Override + public boolean isTagValid(Vec3i location, RelFace face, int tag) { + return parent.isTagValid(location, face, tag); + } + + @Override + public int getTileCount(Vec3i location, RelFace face) { + return parent.getTileCount(location, face); + } + + @Override + public Collection getEntities() { + return parent.getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + return parent.getEntity(entityId); + } + + @Override + public ServerBlockContext push(Vec3i location) { + parent.push(location); + return this; + } + + @Override + public ServerTileStackContext push(Vec3i location, RelFace face) { + parent.push(location, face); + return this; + } + + @Override + public ServerTileContext push(Vec3i location, RelFace face, int layer) { + parent.push(location, face, layer); + return this; + } + + @Override + public Vec3i toAbsolute(Vec3i contextLocation, Vec3i output) { + return parent.toAbsolute(contextLocation, output); + } + + @Override + public Vec3i toContext(Vec3i absoluteLocation, Vec3i output) { + return parent.toContext(absoluteLocation, output); + } + + @Override + public AbsFace toAbsolute(RelFace contextFace) { + return parent.toAbsolute(contextFace); + } + + @Override + public RelFace toContext(AbsFace absoluteFace) { + return parent.toContext(absoluteFace); + } + + @Override + public Server getServer() { + return parent.getServer(); + } + + @Override + public Random getRandom() { + return parent.getRandom(); + } + + @Override + public double getTickLength() { + return parent.getTickLength(); + } + + @Override + public ServerTileContext.Logic logic() { + return logic; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java new file mode 100644 index 0000000..57ff66c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java @@ -0,0 +1,145 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context.impl; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.world.context.ServerTileContext; + +public class ReportingServerContext extends FilterServerContext { + + public static interface ChangeListener { + + void onBlockSet(Vec3i location, BlockData block); + + void onTileAdded(Vec3i location, RelFace face, TileData tile); + + void onTileRemoved(Vec3i location, RelFace face, int tag); + + void onEntityAdded(EntityData entity); + + void onEntityRemoved(long entityId); + + void onEntityChanged(SE entity, StateChange change); + + void onTimeChanged(float change); + + } + + private ChangeListener listener = null; + private boolean passToParent = true; + + /** + * Creates a new {@link ReportingServerContext} instance that delegates + * method calls to the specified parent context. Write methods are always + * passed, disable with {@link #setPassToParent(boolean)}. No listener is + * set, set a listener with {@link #withListener(ChangeListener)}. + * + * @param parent the parent context + */ + public ReportingServerContext(ServerTileContext parent) { + super(parent); + } + + public ReportingServerContext withListener(ChangeListener listener) { + this.listener = listener; + return this; + } + + public ReportingServerContext setPassToParent(boolean pass) { + this.passToParent = pass; + return this; + } + + @Override + public void setBlock(Vec3i location, BlockData block) { + if (passToParent) { + super.setBlock(location, block); + } + if (listener != null) { + listener.onBlockSet(location, block); + } + } + + @Override + public void addTile(Vec3i location, RelFace face, TileData tile) { + if (passToParent) { + super.addTile(location, face, tile); + } + if (listener != null) { + listener.onTileAdded(location, face, tile); + } + } + + @Override + public void removeTile(Vec3i location, RelFace face, int tag) { + if (passToParent) { + super.removeTile(location, face, tag); + } + if (listener != null) { + listener.onTileRemoved(location, face, tag); + } + } + + @Override + public void addEntity(EntityData entity) { + if (passToParent) { + super.addEntity(entity); + } + if (listener != null) { + listener.onEntityAdded(entity); + } + } + + @Override + public void removeEntity(long entityId) { + if (passToParent) { + super.removeEntity(entityId); + } + if (listener != null) { + listener.onEntityRemoved(entityId); + } + } + + @Override + public void changeEntity(SE entity, StateChange change) { + if (passToParent) { + super.changeEntity(entity, change); + } + if (listener != null) { + listener.onEntityChanged(entity, change); + } + } + + @Override + public void advanceTime(float change) { + if (passToParent) { + super.advanceTime(change); + } + if (listener != null) { + listener.onTimeChanged(change); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java new file mode 100644 index 0000000..a73d2b0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java @@ -0,0 +1,59 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context.impl; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.ServerTileContext; + +public class RotatingServerContext extends TransformingServerContext { + + private final AbsFace up; + + public RotatingServerContext(ServerTileContext parent, AbsFace up) { + super(parent); + this.up = up; + } + + public AbsFace getUp() { + return up; + } + + @Override + protected void transform(Vec3i userLocation, Vec3i output) { + GenericChunks.resolve(userLocation, up, output); + } + + @Override + protected void untransform(Vec3i parentLocation, Vec3i output) { + GenericChunks.relativize(parentLocation, up, output); + } + + @Override + protected RelFace transform(RelFace userFace) { + return userFace.resolve(up).relativize(AbsFace.POS_Z); + } + + @Override + protected RelFace untransform(RelFace parentFace) { + return parentFace.resolve(AbsFace.POS_Z).relativize(up); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java new file mode 100644 index 0000000..9c0be6c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java @@ -0,0 +1,284 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.context.impl; + +import java.util.ArrayList; +import java.util.List; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileStackContext; + +public abstract class TransformingServerContext extends FilterServerContext { + + private final Vec3i location = new Vec3i(); + private boolean isLocationValid = false; + + private RelFace face = null; + + private final List vectorCache = new ArrayList<>(1); + + public TransformingServerContext(ServerTileContext parent) { + super(parent); + } + + protected abstract void transform(Vec3i userLocation, Vec3i output); + + protected abstract void untransform(Vec3i parentLocation, Vec3i output); + + protected abstract RelFace transform(RelFace userFace); + + protected abstract RelFace untransform(RelFace parentFace); + + protected void invalidateCache() { + isLocationValid = false; + face = null; + } + + private Vec3i grabVector(Vec3i userVector) { + Vec3i parentVector; + + if (vectorCache.isEmpty()) { + parentVector = new Vec3i(); + } else { + parentVector = vectorCache.remove(vectorCache.size() - 1); + } + + transform(userVector, parentVector); + + return parentVector; + } + + private void releaseVector(Vec3i parentVector) { + vectorCache.add(parentVector); + } + + @Override + public Vec3i getLocation() { + // Always invoke parent method to allow parent to determine validity + Vec3i parentLocation = super.getLocation(); + + if (!isLocationValid) { + untransform(parentLocation, location); + isLocationValid = true; + } + + return location; + } + + @Override + public RelFace getFace() { + // Always invoke parent method to allow parent to determine validity + RelFace parentFace = super.getFace(); + + if (face == null) { + face = untransform(parentFace); + } + + return face; + } + + @Override + public void pop() { + super.pop(); + invalidateCache(); + } + + @Override + public ServerBlockContext push(Vec3i userLocation) { + Vec3i parentLocation = grabVector(userLocation); + super.push(parentLocation); + releaseVector(parentLocation); + + location.set(userLocation.x, userLocation.y, userLocation.z); + isLocationValid = true; + face = null; + + return this; + } + + @Override + public ServerTileStackContext push(Vec3i userLocation, RelFace userFace) { + Vec3i parentLocation = grabVector(userLocation); + super.push(parentLocation, transform(userFace)); + releaseVector(parentLocation); + + location.set(userLocation.x, userLocation.y, userLocation.z); + isLocationValid = true; + face = userFace; + + return this; + } + + @Override + public ServerTileContext push(Vec3i userLocation, RelFace userFace, int layer) { + Vec3i parentLocation = grabVector(userLocation); + super.push(parentLocation, transform(userFace), layer); + releaseVector(parentLocation); + + location.set(userLocation.x, userLocation.y, userLocation.z); + isLocationValid = true; + face = userFace; + + return this; + } + + @Override + public Vec3i toAbsolute(Vec3i contextLocation, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + transform(contextLocation, output); + + return super.toAbsolute(output, output); + } + + @Override + public Vec3i toContext(Vec3i absoluteLocation, Vec3i output) { + output = super.toContext(absoluteLocation, output); + untransform(output, output); + return output; + } + + @Override + public AbsFace toAbsolute(RelFace contextFace) { + return super.toAbsolute(transform(contextFace)); + } + + @Override + public RelFace toContext(AbsFace absoluteFace) { + return untransform(super.toContext(absoluteFace)); + } + + @Override + public boolean isLocationLoaded(Vec3i userLocation) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.isLocationLoaded(parentLocation); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public BlockData getBlock(Vec3i userLocation) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.getBlock(parentLocation); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public void setBlock(Vec3i userLocation, BlockData block) { + Vec3i parentLocation = grabVector(userLocation); + + try { + super.setBlock(parentLocation, block); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public boolean hasTile(Vec3i userLocation, RelFace userFace, int layer) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.hasTile(parentLocation, transform(userFace), layer); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public TileData getTile(Vec3i userLocation, RelFace userFace, int layer) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.getTile(parentLocation, transform(userFace), layer); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public boolean isTagValid(Vec3i userLocation, RelFace userFace, int tag) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.isTagValid(parentLocation, transform(userFace), tag); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public TileData getTileByTag(Vec3i userLocation, RelFace userFace, int tag) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.getTileByTag(parentLocation, transform(userFace), tag); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public int getTileCount(Vec3i userLocation, RelFace userFace) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.getTileCount(parentLocation, transform(userFace)); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public void addTile(Vec3i userLocation, RelFace userFace, TileData tile) { + Vec3i parentLocation = grabVector(userLocation); + + try { + super.addTile(parentLocation, transform(userFace), tile); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public void removeTile(Vec3i userLocation, RelFace userFace, int tag) { + Vec3i parentLocation = grabVector(userLocation); + + try { + super.removeTile(parentLocation, transform(userFace), tag); + } finally { + releaseVector(parentLocation); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java b/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java index 7725612..3f87caf 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java @@ -15,12 +15,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.entity; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.server.world.TickContext; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; public class EntityLogic extends Namespaced { @@ -28,7 +28,7 @@ public class EntityLogic extends Namespaced { super(id); } - public void tick(EntityData entity, TickContext context) { + public void tick(EntityData entity, ServerWorldContext context) { entity.incrementAge(context.getTickLength()); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogicRegistry.java b/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogicRegistry.java index d8b05d4..a3ecd20 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogicRegistry.java +++ b/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogicRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.entity; import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java index ffb5c06..c91594e 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.generation; import java.io.DataInputStream; @@ -23,16 +23,31 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.Objects; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; +import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.GravityModelRegistry; +import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.DefaultWorldLogic; public abstract class AbstractWorldGenerator extends WorldGenerator { private final Class hintClass; + + private final GravityModel gravityModel; + + private final Server server; - public AbstractWorldGenerator(String id, Class hintClass) { + public AbstractWorldGenerator(String id, Server server, Class hintClass, String gravityModelId) { super(id); this.hintClass = Objects.requireNonNull(hintClass, "hintClass"); + this.gravityModel = GravityModelRegistry.getInstance().create(Objects.requireNonNull(gravityModelId, "gravityModelId")); + this.server = server; + + if (this.gravityModel == null) { + throw new IllegalArgumentException("Gravity model with ID \"" + gravityModelId + "\" not found"); + } } @Override @@ -56,12 +71,32 @@ public abstract class AbstractWorldGenerator extends WorldGenerator { protected abstract boolean checkIsChunkReady(H hint); - protected H getHint(ChunkData chunk) { + protected H getHint(DefaultChunkData chunk) { return hintClass.cast(chunk.getGenerationHint()); } - protected void setHint(ChunkData chunk, H hint) { + protected void setHint(DefaultChunkData chunk, H hint) { chunk.setGenerationHint(hint); } + + @Override + public GravityModel getGravityModel() { + return gravityModel; + } + + @Override + public Server getServer() { + return server; + } + + @Override + public DefaultWorldLogic getWorldLogic() { + return server.getWorld(); + } + + @Override + public DefaultWorldData getWorldData() { + return server.getWorld().getData(); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java index afed281..200fdfb 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java @@ -15,18 +15,22 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.generation; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.DefaultWorldLogic; public abstract class WorldGenerator extends Namespaced { @@ -35,12 +39,20 @@ public abstract class WorldGenerator extends Namespaced { // package-private constructor; extend AbstractWorldGeneration } - public abstract ChunkData generate(Vec3i chunkPos, WorldData world); + public abstract DefaultChunkData generate(Vec3i chunkPos); public abstract Object readGenerationHint(DataInputStream input) throws IOException, DecodingException; public abstract void writeGenerationHint(DataOutputStream output, Object hint) throws IOException; public abstract boolean isChunkReady(Object hint); + + public abstract GravityModel getGravityModel(); + + public abstract Vec3 suggestSpawnLocation(); + + public abstract Server getServer(); + public abstract DefaultWorldLogic getWorldLogic(); + public abstract DefaultWorldData getWorldData(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/Planet.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/Planet.java new file mode 100644 index 0000000..161e2c0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/Planet.java @@ -0,0 +1,89 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.planet; + +import ru.windcorp.progressia.common.world.DefaultChunkData; + +public class Planet { + + private final int radiusInChunks; + + private final PlanetGravityModel.Settings gravityModelSettings; + + public Planet( + int radiusInChunks, + float surfaceGravitationalAcceleration, + float curvature, + float innerGravityRadius + ) { + this.radiusInChunks = radiusInChunks; + this.gravityModelSettings = new PlanetGravityModel.Settings( + surfaceGravitationalAcceleration, + curvature, + innerGravityRadius + ); + } + + /** + * @return the radiusInChunks + */ + public int getRadiusInChunks() { + return radiusInChunks; + } + + public float getRadius() { + return radiusInChunks * DefaultChunkData.BLOCKS_PER_CHUNK + DefaultChunkData.CHUNK_RADIUS; + } + + public int getDiameterInChunks() { + return radiusInChunks * 2 + 1; + } + + public float getDiameter() { + return getDiameterInChunks() * DefaultChunkData.BLOCKS_PER_CHUNK; + } + + /** + * @return the curvature + */ + public float getCurvature() { + return gravityModelSettings.curvature; + } + + /** + * @return the innerGravityRadius + */ + public float getInnerGravityRadius() { + return gravityModelSettings.innerRadius; + } + + /** + * @return the surfaceGravitationalAcceleration + */ + public float getSurfaceGravitationalAcceleration() { + return gravityModelSettings.surfaceGravitationalAcceleration; + } + + /** + * @return the gravityModelSettings + */ + public PlanetGravityModel.Settings getGravityModelSettings() { + return gravityModelSettings; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetFeatureGenerator.java new file mode 100644 index 0000000..97e2424 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetFeatureGenerator.java @@ -0,0 +1,75 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.planet; + +import java.util.List; +import java.util.Map; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.generation.surface.Surface; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeature; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeatureGenerator; + +public class PlanetFeatureGenerator { + + private final PlanetGenerator parent; + + private final Map surfaceGenerators; + + public PlanetFeatureGenerator(PlanetGenerator generator, List features) { + this.parent = generator; + + int seaLevel = (int) parent.getPlanet().getRadius(); + this.surfaceGenerators = AbsFace.mapToFaces(face -> new SurfaceFeatureGenerator( + new Surface(face, seaLevel), + features + )); + } + + public PlanetGenerator getGenerator() { + return parent; + } + + public void generateFeatures(Server server, DefaultChunkData chunk) { + if (isOrdinaryChunk(chunk.getPosition())) { + generateOrdinaryFeatures(server, chunk); + } else { + generateBorderFeatures(server, chunk); + } + + chunk.setGenerationHint(true); + } + + private boolean isOrdinaryChunk(Vec3i chunkPos) { + Vec3i sorted = VectorUtil.sortAfterAbs(chunkPos, null); + return sorted.x != sorted.y; + } + + private void generateOrdinaryFeatures(Server server, DefaultChunkData chunk) { + surfaceGenerators.get(chunk.getUp()).generateFeatures(server, chunk); + } + + private void generateBorderFeatures(Server server, DefaultChunkData chunk) { + // Do nothing + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java new file mode 100644 index 0000000..0b626c4 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java @@ -0,0 +1,113 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.planet; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.FloatRangeMap; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.DecodingException; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeature; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; + +public class PlanetGenerator extends AbstractWorldGenerator { + + private final Planet planet; + + private final PlanetTerrainGenerator terrainGenerator; + private final PlanetFeatureGenerator featureGenerator; + + public PlanetGenerator( + String id, + Server server, + Planet planet, + SurfaceFloatField heightMap, + FloatRangeMap layers, + List features + ) { + super(id, server, Boolean.class, "Test:PlanetGravityModel"); + + this.planet = planet; + + PlanetGravityModel model = (PlanetGravityModel) this.getGravityModel(); + model.configure(planet.getGravityModelSettings()); + + this.terrainGenerator = new PlanetTerrainGenerator(this, heightMap, layers); + this.featureGenerator = new PlanetFeatureGenerator(this, features); + + + } + + /** + * @return the planet + */ + public Planet getPlanet() { + return planet; + } + + @Override + public Vec3 suggestSpawnLocation() { + return new Vec3(7f, 1f, getPlanet().getRadius() + 10); + } + + @Override + protected Boolean doReadGenerationHint(DataInputStream input) throws IOException, DecodingException { + return input.readBoolean(); + } + + @Override + protected void doWriteGenerationHint(DataOutputStream output, Boolean hint) throws IOException { + output.writeBoolean(hint); + } + + @Override + protected boolean checkIsChunkReady(Boolean hint) { + return Boolean.TRUE.equals(hint); // Avoid NPE + } + + @Override + public DefaultChunkData generate(Vec3i chunkPos) { + VectorUtil.iterateCuboidAround(chunkPos, 3, r -> conjureTerrain(r)); + DefaultChunkData chunk = getWorldData().getChunk(chunkPos); + + if (!isChunkReady(chunk.getGenerationHint())) { + featureGenerator.generateFeatures(getServer(), chunk); + } + + return chunk; + } + + private void conjureTerrain(Vec3i chunkPos) { + getServer().getLoadManager().getChunkManager().loadChunk(chunkPos); + DefaultChunkData chunk = getWorldData().getChunk(chunkPos); + + if (chunk == null) { + chunk = terrainGenerator.generateTerrain(getServer(), chunkPos); + getWorldData().addChunk(chunk); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGravityModel.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGravityModel.java new file mode 100644 index 0000000..e2545b5 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGravityModel.java @@ -0,0 +1,193 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.planet; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.DecodingException; +import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.rels.AbsFace; + +import static java.lang.Math.*; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class PlanetGravityModel extends GravityModel { + + public static class Settings { + public float surfaceGravitationalAcceleration; + public float curvature; + public float innerRadius; + + public Settings() {} + + public Settings(float surfaceGravitationalAcceleration, float curvature, float innerRadius) { + this.surfaceGravitationalAcceleration = surfaceGravitationalAcceleration; + this.curvature = curvature; + this.innerRadius = innerRadius; + } + + public void copyFrom(Settings copyFrom) { + this.surfaceGravitationalAcceleration = copyFrom.surfaceGravitationalAcceleration; + this.curvature = copyFrom.curvature; + this.innerRadius = copyFrom.innerRadius; + } + + public void read(DataInput input) throws IOException, DecodingException { + surfaceGravitationalAcceleration = input.readFloat(); + curvature = input.readFloat(); + innerRadius = input.readFloat(); + } + + public void write(DataOutput output) throws IOException { + output.writeFloat(surfaceGravitationalAcceleration); + output.writeFloat(curvature); + output.writeFloat(innerRadius); + } + } + + private Settings settings = new Settings(); + + public PlanetGravityModel(String id) { + super(id); + } + + public float getSurfaceGravitationalAcceleration() { + return settings.surfaceGravitationalAcceleration; + } + + public float getCurvature() { + return settings.curvature; + } + + public float getInnerRadius() { + return settings.innerRadius; + } + + public void configure(Settings settings) { + this.settings = settings; + } + + @Override + protected void doGetGravity(Vec3 pos, Vec3 output) { + float r = getInnerRadius(); + float c = getCurvature(); + + // Change to a CS where (0;0;0) is the center of the center chunk + float px = pos.x - DefaultChunkData.CHUNK_RADIUS + 0.5f; + float py = pos.y - DefaultChunkData.CHUNK_RADIUS + 0.5f; + float pz = pos.z - DefaultChunkData.CHUNK_RADIUS + 0.5f; + + // Assume weightlessness when too close to center + if ((px*px + py*py + pz*pz) < r*r) { + output.set(0, 0, 0); + return; + } + + // Cache absolute coordinates + float ax = abs(px); + float ay = abs(py); + float az = abs(pz); + + // Determine maximum and middle coordinates by absolute value + final float maxAbs; + final float midAbs; + + // herptyderp + if (ax > ay) { + if (ax > az) { + maxAbs = ax; + midAbs = ay > az ? ay : az; + } else { + maxAbs = az; + midAbs = ax; + } + } else { + if (ay > az) { + maxAbs = ay; + midAbs = ax > az ? ax : az; + } else { + maxAbs = az; + midAbs = ay; + } + } + + output.x = maxAbs - ax < c ? (px > 0 ? +1 : -1) : 0; + output.y = maxAbs - ay < c ? (py > 0 ? +1 : -1) : 0; + output.z = maxAbs - az < c ? (pz > 0 ? +1 : -1) : 0; + + if (maxAbs - midAbs < c) { + output.normalize(); + computeEdgeGravity(output.x, output.y, output.z, px, py, pz, output); + } else { + assert output.dot(output) == 1 : "maxAbs - midAbs = " + maxAbs + " - " + midAbs + " > " + c + " yet l*l != 1"; + } + + output.mul(-getSurfaceGravitationalAcceleration()); + } + + private void computeEdgeGravity(float lx, float ly, float lz, float rx, float ry, float rz, Vec3 output) { + // da math is gud, no worry + // - Javapony + + float c = getCurvature(); + + if (lx == 0) rx = 0; + if (ly == 0) ry = 0; + if (lz == 0) rz = 0; + + float scalarProduct = rx*lx + ry*ly + rz*lz; + float rSquared = rx*rx + ry*ry + rz*rz; + + float distanceAlongEdge = scalarProduct - (float) sqrt( + scalarProduct*scalarProduct - rSquared + c*c + ); + + output.set(lx, ly, lz).mul(-distanceAlongEdge).add(rx, ry, rz).div(c); + + final float f = (float) sqrt(3.0/2); + + if (signum(lx) != signum(output.x)) { + computeEdgeGravity(0, ly*f, lz*f, rx, ry, rz, output); + } else if (signum(ly) != signum(output.y)) { + computeEdgeGravity(lx*f, 0, lz*f, rx, ry, rz, output); + } else if (signum(lz) != signum(output.z)) { + computeEdgeGravity(lx*f, ly*f, 0, rx, ry, rz, output); + } + } + + @Override + protected AbsFace doGetDiscreteUp(Vec3i chunkPos) { + AbsFace rounded = AbsFace.roundToFace(chunkPos.x, chunkPos.y, chunkPos.z); + return rounded == null ? AbsFace.POS_Z : rounded; + } + + @Override + protected void doReadSettings(DataInput input) throws IOException, DecodingException { + this.settings.read(input); + } + + @Override + protected void doWriteSettings(DataOutput output) throws IOException { + this.settings.write(output); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java new file mode 100644 index 0000000..dba3b8a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java @@ -0,0 +1,113 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.planet; + +import java.util.Map; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.FloatRangeMap; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.generation.surface.Surface; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceTerrainGenerator; +import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; + +class PlanetTerrainGenerator { + + private final PlanetGenerator parent; + private final Map surfaceGenerators; + + public PlanetTerrainGenerator( + PlanetGenerator generator, + SurfaceFloatField heightMap, + FloatRangeMap layers + ) { + this.parent = generator; + + int seaLevel = (int) parent.getPlanet().getRadius(); + SurfaceFloatField adjustedHeightMap = (f, n, w) -> heightMap.get(f, n, w) + generator.getPlanet().getRadius(); + + this.surfaceGenerators = AbsFace.mapToFaces( + face -> new SurfaceTerrainGenerator( + new Surface(face, seaLevel), + adjustedHeightMap, + layers + ) + ); + } + + public PlanetGenerator getGenerator() { + return parent; + } + + public DefaultChunkData generateTerrain(Server server, Vec3i chunkPos) { + DefaultChunkData chunk = new DefaultChunkData(chunkPos, getGenerator().getWorldData()); + + if (isOrdinaryChunk(chunkPos)) { + generateOrdinaryTerrain(server, chunk); + } else { + generateBorderTerrain(server, chunk); + } + + chunk.setGenerationHint(false); + + return chunk; + } + + private boolean isOrdinaryChunk(Vec3i chunkPos) { + Vec3i sorted = VectorUtil.sortAfterAbs(chunkPos, null); + return sorted.x != sorted.y; + } + + private void generateOrdinaryTerrain(Server server, DefaultChunkData chunk) { + surfaceGenerators.get(chunk.getUp()).generateTerrain(server, chunk); + } + + private void generateBorderTerrain(Server server, DefaultChunkData chunk) { + BlockData stone = BlockDataRegistry.getInstance().get("Test:Stone"); + BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); + + float radius = parent.getPlanet().getRadius(); + + Vec3 biw = new Vec3(); + + GenericChunks.forEachBiC(bic -> { + + biw.set( + Coordinates.getInWorld(chunk.getX(), bic.x), + Coordinates.getInWorld(chunk.getY(), bic.y), + Coordinates.getInWorld(chunk.getZ(), bic.z) + ); + + biw.sub(DefaultChunkData.CHUNK_RADIUS - 0.5f); + VectorUtil.sortAfterAbs(biw, biw); + + chunk.setBlock(bic, biw.x <= radius ? stone : air, false); + + }); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java new file mode 100644 index 0000000..08c9308 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java @@ -0,0 +1,79 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface; + +import java.util.Random; + +import glm.Glm; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.CoordinatePacker; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceContextImpl; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; + +public class Surface { + + private final AbsFace up; + private final int seaLevel; + + public Surface(AbsFace up, int seaLevel) { + this.up = up; + this.seaLevel = seaLevel; + } + + /** + * @return the up + */ + public AbsFace getUp() { + return up; + } + + /** + * @return the seaLevel + */ + public int getSeaLevel() { + return seaLevel; + } + + public SurfaceWorldContext createContext(Server server, ChunkGenericRO chunk, long seed) { + + Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) ^ seed); + + SurfaceContextImpl context = new SurfaceContextImpl((ServerTileContext) server.createAbsoluteContext(), this); + context.setRandom(random); + + Vec3i tmpA = new Vec3i(); + Vec3i tmpB = new Vec3i(); + + chunk.getMinBIW(tmpA); + chunk.getMaxBIW(tmpB); + + context.toContext(tmpA, tmpA); + context.toContext(tmpB, tmpB); + + Glm.min(tmpA, tmpB, context.getMin()); + Glm.max(tmpA, tmpB, context.getMax()); + + return context; + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeature.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeature.java new file mode 100644 index 0000000..8430168 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeature.java @@ -0,0 +1,46 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface; + +import java.util.List; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.server.world.context.ServerContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; + +public abstract class SurfaceFeature extends Namespaced { + + public SurfaceFeature(String id) { + super(id); + } + + public abstract void process(SurfaceWorldContext context); + + protected static double randomDouble(ServerContext context, double from, double to) { + return from + (to - from) * context.getRandom().nextDouble(); + } + + protected static double stretch(double t, double from, double to) { + return from + (to - from) * t; + } + + protected static T pickRandom(ServerContext context, List from) { + return from.get(context.getRandom().nextInt(from.size())); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java new file mode 100644 index 0000000..3548184 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java @@ -0,0 +1,54 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface; + +import java.util.ArrayList; +import java.util.List; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; + +public class SurfaceFeatureGenerator { + + private final Surface surface; + + private final List features; + + public SurfaceFeatureGenerator(Surface surface, List features) { + this.surface = surface; + this.features = new ArrayList<>(features); + } + + /** + * @return the surface + */ + public Surface getSurface() { + return surface; + } + + public void generateFeatures(Server server, DefaultChunkData chunk) { + SurfaceWorldContext context = surface.createContext(server, chunk, 0); + + for (SurfaceFeature feature : features) { + feature.process(context); + } + + chunk.setGenerationHint(true); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFloatField.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFloatField.java new file mode 100644 index 0000000..81506f1 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFloatField.java @@ -0,0 +1,34 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; + +@FunctionalInterface +public interface SurfaceFloatField { + + float get(AbsFace face, float x, float y); + + default float get(SurfaceBlockContext context) { + Vec3i location = context.getLocation(); + return get(context.getSurface().getUp(), location.x, location.y); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java new file mode 100644 index 0000000..35b4a58 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java @@ -0,0 +1,89 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.FloatRangeMap; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.rels.AxisRotations; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; + +public class SurfaceTerrainGenerator { + + private final Surface surface; + + private final SurfaceFloatField heightMap; + private final FloatRangeMap layers; + + public SurfaceTerrainGenerator(Surface surface, SurfaceFloatField heightMap, FloatRangeMap layers) { + this.surface = surface; + this.heightMap = heightMap; + this.layers = layers; + } + + public void generateTerrain(Server server, DefaultChunkData chunk) { + + Vec3i relBIC = new Vec3i(); + + Vec3 offset = new Vec3(chunk.getMinX(), chunk.getMinY(), chunk.getMinZ()); + AxisRotations.relativize(offset, chunk.getUp(), offset); + + SurfaceWorldContext context = surface.createContext(server, chunk, 0); + + for (relBIC.x = 0; relBIC.x < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.x) { + for (relBIC.y = 0; relBIC.y < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.y) { + generateColumn(chunk, relBIC, offset, context); + } + } + + } + + public void generateColumn(DefaultChunkData chunk, Vec3i relBIC, Vec3 offset, SurfaceWorldContext context) { + + int north = (int) (relBIC.x + offset.x); + int west = (int) (relBIC.y + offset.y); + + float relSurface = heightMap.get(chunk.getUp(), north, west) - offset.z + DefaultChunkData.CHUNK_RADIUS - 0.5f; + Vec3i location = Vectors.grab3i(); + + for (relBIC.z = 0; relBIC.z < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.z) { + float depth = relSurface - relBIC.z; + int altitude = (int) (relBIC.z + offset.z); + + location.set(north, west, altitude); + SurfaceBlockContext blockContext = context.push(location); + + BlockData block = layers.get(depth).get(blockContext, depth); + + blockContext.pop(); + + chunk.resolve(relBIC, relBIC); + chunk.setBlock(relBIC, block, false); + chunk.relativize(relBIC, relBIC); + } + + Vectors.release(location); + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTopLayerFeature.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTopLayerFeature.java new file mode 100644 index 0000000..d96d68b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTopLayerFeature.java @@ -0,0 +1,64 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; + +public abstract class SurfaceTopLayerFeature extends SurfaceFeature { + + public SurfaceTopLayerFeature(String id) { + super(id); + } + + protected abstract void processTopBlock(SurfaceBlockContext context); + + protected abstract boolean isSolid(SurfaceBlockContext context); + + @Override + public void process(SurfaceWorldContext context) { + Vec3i cursor = new Vec3i(); + + context.forEachOnFloor(pos -> { + + cursor.set(pos.x, pos.y, pos.z); + + if (!isSolid(context.push(cursor))) { + context.pop(); + return; + } + context.pop(); + + for (cursor.z += 1; cursor.z <= context.getMaxZ() + 1; ++cursor.z) { + SurfaceBlockContext blockContext = context.push(cursor); + + if (!isSolid(blockContext)) { + processTopBlock(blockContext.pushRelative(0, 0, -1)); + context.pop(); + context.pop(); + return; + } + + context.pop(); + } + + }); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java new file mode 100644 index 0000000..5ec131c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java @@ -0,0 +1,28 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; + +@FunctionalInterface +public interface TerrainLayer { + + BlockData get(SurfaceBlockContext context, float depth); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceBlockContext.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceBlockContext.java new file mode 100644 index 0000000..64531fb --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceBlockContext.java @@ -0,0 +1,87 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; + +public interface SurfaceBlockContext extends ServerBlockContext, SurfaceWorldContext { + + public interface Logic extends ServerBlockContext.Logic, SurfaceWorldContext.Logic { + + @Override + SurfaceBlockContext data(); + + @Override + default SurfaceBlockContext.Logic pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default SurfaceBlockContext.Logic pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default SurfaceBlockContext.Logic pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default SurfaceTileStackContext.Logic push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default SurfaceTileContext.Logic push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + + } + + @Override + SurfaceBlockContext.Logic logic(); + + @Override + default SurfaceBlockContext pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default SurfaceBlockContext pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default SurfaceBlockContext pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default SurfaceTileStackContext push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default SurfaceTileContext push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContext.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContext.java new file mode 100644 index 0000000..a69d60b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContext.java @@ -0,0 +1,136 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface.context; + +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.server.world.generation.surface.Surface; + +public interface SurfaceContext { + + /** + * Returns the {@link Surface} object relevant to this context. + * + * @return the surface details + */ + Surface getSurface(); + + /** + * Returns lower bounds (inclusive) on the coordinates of the requested + * region. + * + * @return the coordinates of the minimum corner of the region that + * should be processed + */ + Vec3i getMin(); + + /** + * Returns upper bounds (inclusive) on the coordinates of the requested + * region. + * + * @return the coordinates of the maximum corner of the region that + * should be processed + */ + Vec3i getMax(); + + /* + * Convenience methods + */ + + default int getMinX() { + return getMin().x; + } + + default int getMinY() { + return getMin().y; + } + + default int getMinZ() { + return getMin().z; + } + + default int getMaxX() { + return getMax().x; + } + + default int getMaxY() { + return getMax().y; + } + + default int getMaxZ() { + return getMax().z; + } + + default boolean isRequested(int x, int y, int z) { + Vec3i min = getMin(); + Vec3i max = getMax(); + return (min.x <= x && x <= max.x) && (min.y <= y && y <= max.y) && (min.z <= z && z <= max.z); + } + + default boolean isRequested(Vec3i location) { + return isRequested(location.x, location.y, location.z); + } + + default void forEachRequested(Consumer action) { + Vec3i min = getMin(); + Vec3i max = getMax(); + VectorUtil.iterateCuboid( + min.x, + min.y, + min.z, + max.x + 1, + max.y + 1, + max.z + 1, + action + ); + } + + /** + * Provided vectors have z set to {@link #getMinZ()}. + */ + default void forEachOnFloor(Consumer action) { + forEachOnLayer(action, getMinZ()); + } + + /** + * Provided vectors have z set to {@link #getMaxZ()}. + */ + default void forEachOnCeiling(Consumer action) { + forEachOnLayer(action, getMaxZ()); + } + + /** + * Provided vectors have z set to layer. + */ + default void forEachOnLayer(Consumer action, int layer) { + Vec3i min = getMin(); + Vec3i max = getMax(); + VectorUtil.iterateCuboid( + min.x, + min.y, + layer, + max.x + 1, + max.y + 1, + layer + 1, + action + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImpl.java new file mode 100644 index 0000000..6050c49 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImpl.java @@ -0,0 +1,114 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface.context; + +import java.util.Random; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.impl.RotatingServerContext; +import ru.windcorp.progressia.server.world.generation.surface.Surface; + +public class SurfaceContextImpl extends RotatingServerContext implements SurfaceTileContext { + + final Surface surface; + final Vec3i min = new Vec3i(); + final Vec3i max = new Vec3i(); + private Random random; + + private final SurfaceContextImplLogic logic; + + public SurfaceContextImpl(ServerTileContext parent, Surface surface) { + super(parent, surface.getUp()); + this.logic = new SurfaceContextImplLogic(this); + + this.surface = surface; + } + + @Override + protected void transform(Vec3i userLocation, Vec3i output) { + output.set(userLocation.x, userLocation.y, userLocation.z); + output.z += surface.getSeaLevel(); + super.transform(output, output); + } + + @Override + protected void untransform(Vec3i parentLocation, Vec3i output) { + super.untransform(parentLocation, output); + output.z -= surface.getSeaLevel(); + } + + @Override + public Surface getSurface() { + return surface; + } + + /** + * {@inheritDoc} + * + * @implNote can rw + */ + @Override + public Vec3i getMin() { + return min; + } + + /** + * {@inheritDoc} + * + * @implNote can rw + */ + @Override + public Vec3i getMax() { + return max; + } + + @Override + public Random getRandom() { + return random; + } + + public void setRandom(Random random) { + this.random = random; + } + + @Override + public SurfaceContextImplLogic logic() { + return logic; + } + + @Override + public SurfaceTileContext push(Vec3i location) { + super.push(location); + return this; + } + + @Override + public SurfaceTileContext push(Vec3i location, RelFace face) { + super.push(location, face); + return this; + } + + @Override + public SurfaceTileContext push(Vec3i location, RelFace face, int layer) { + super.push(location, face, layer); + return this; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImplLogic.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImplLogic.java new file mode 100644 index 0000000..cbf9b88 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImplLogic.java @@ -0,0 +1,72 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.impl.DefaultServerContextLogic; +import ru.windcorp.progressia.server.world.generation.surface.Surface; + +public class SurfaceContextImplLogic extends DefaultServerContextLogic implements SurfaceTileContext.Logic { + + private final SurfaceContextImpl surfaceParent; + + public SurfaceContextImplLogic(SurfaceContextImpl surfaceParent) { + super(surfaceParent); + this.surfaceParent = surfaceParent; + } + + @Override + public Surface getSurface() { + return this.surfaceParent.surface; + } + + @Override + public Vec3i getMin() { + return this.surfaceParent.min; + } + + @Override + public Vec3i getMax() { + return this.surfaceParent.max; + } + + @Override + public SurfaceContextImpl data() { + return this.surfaceParent; + } + + @Override + public SurfaceTileContext.Logic push(Vec3i location) { + super.push(location); + return this; + } + + @Override + public SurfaceTileContext.Logic push(Vec3i location, RelFace face) { + super.push(location, face); + return this; + } + + @Override + public SurfaceTileContext.Logic push(Vec3i location, RelFace face, int layer) { + super.push(location, face, layer); + return this; + } + +} \ No newline at end of file diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileContext.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileContext.java new file mode 100644 index 0000000..ce28c6e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileContext.java @@ -0,0 +1,54 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface.context; + +import ru.windcorp.progressia.server.world.context.ServerTileContext; + +public interface SurfaceTileContext extends ServerTileContext, SurfaceTileStackContext { + + public interface Logic extends ServerTileContext.Logic, SurfaceTileStackContext.Logic { + + @Override + SurfaceTileContext data(); + + @Override + default SurfaceTileContext.Logic pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default SurfaceTileContext.Logic pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + + } + + @Override + SurfaceTileContext.Logic logic(); + + @Override + default SurfaceTileContext pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default SurfaceTileContext pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileStackContext.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileStackContext.java new file mode 100644 index 0000000..d090e94 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileStackContext.java @@ -0,0 +1,64 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface.context; + +import ru.windcorp.progressia.server.world.context.ServerTileStackContext; + +public interface SurfaceTileStackContext extends ServerTileStackContext, SurfaceBlockContext { + + public interface Logic extends ServerTileStackContext.Logic, SurfaceBlockContext.Logic { + + @Override + SurfaceTileStackContext data(); + + @Override + default SurfaceTileContext.Logic push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default SurfaceTileStackContext.Logic pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default SurfaceTileStackContext.Logic pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + + } + + @Override + SurfaceTileStackContext.Logic logic(); + + @Override + default SurfaceTileContext push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default SurfaceTileStackContext pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default SurfaceTileStackContext pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceWorldContext.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceWorldContext.java new file mode 100644 index 0000000..96a0922 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceWorldContext.java @@ -0,0 +1,54 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.server.world.generation.surface.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; + +public interface SurfaceWorldContext extends ServerWorldContext, SurfaceContext { + + public interface Logic extends ServerWorldContext.Logic, SurfaceContext { + + @Override + SurfaceWorldContext data(); + + @Override + SurfaceBlockContext.Logic push(Vec3i location); + + @Override + SurfaceTileStackContext.Logic push(Vec3i location, RelFace face); + + @Override + SurfaceTileContext.Logic push(Vec3i location, RelFace face, int layer); + + } + + @Override + SurfaceWorldContext.Logic logic(); + + @Override + SurfaceBlockContext push(Vec3i location); + + @Override + SurfaceTileStackContext push(Vec3i location, RelFace face); + + @Override + SurfaceTileContext push(Vec3i location, RelFace face, int layer); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/AddTile.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/AddTile.java index 6e9ea47..238a42f 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/AddTile.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/AddTile.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java index 331a5c4..f7c385b 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java @@ -15,17 +15,16 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.TickAndUpdateUtil; -import ru.windcorp.progressia.server.world.WorldLogic; class BlockTriggeredUpdate extends CachedEvaluation { @@ -39,13 +38,11 @@ class BlockTriggeredUpdate extends CachedEvaluation { public void evaluate(Server server) { Vec3i cursor = new Vec3i(blockInWorld.x, blockInWorld.y, blockInWorld.z); - WorldLogic world = server.getWorld(); - - for (BlockFace face : BlockFace.getFaces()) { - TickAndUpdateUtil.updateTiles(world, cursor, face); + for (AbsFace face : AbsFace.getFaces()) { + TickAndUpdateUtil.updateTiles(server, cursor, face); cursor.add(face.getVector()); - TickAndUpdateUtil.updateBlock(world, cursor); - TickAndUpdateUtil.updateTiles(world, cursor, face.getCounter()); + TickAndUpdateUtil.updateBlock(server, cursor); + TickAndUpdateUtil.updateTiles(server, cursor, face.getCounter()); cursor.sub(face.getVector()); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedBlockChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedBlockChange.java index b005285..62cedac 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedBlockChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedBlockChange.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChange.java index e1eb5ca..d5db70a 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChange.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChunkChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChunkChange.java index d98c001..ef4a8cf 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChunkChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChunkChange.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedEvaluation.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedEvaluation.java index da865b4..5fe1320 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedEvaluation.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedEvaluation.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedTileChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedTileChange.java index 1b6cde2..7d27be0 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedTileChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedTileChange.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.Objects; @@ -58,9 +58,8 @@ public class CachedTileChange

    extends CachedChunkCha if (my.getTag() == -1 || other.getTag() == -1) return false; - return Glm.equals(my.getBlockInWorld(), other.getBlockInWorld()) - && (my.getFace() == other.getFace()) - && (my.getTag() == other.getTag()); + return Glm.equals(my.getBlockInWorld(), other.getBlockInWorld()) && (my.getFace() == other.getFace()) + && (my.getTag() == other.getTag()); } @Override @@ -69,7 +68,7 @@ public class CachedTileChange

    extends CachedChunkCha Vec3i biw = packet.getBlockInWorld(); return getClass().getSimpleName() + " (" + biw.x + "; " + biw.y + "; " + biw.z + "; " + packet.getFace() - + "; tag: " + packet.getTag() + ")"; + + "; tag: " + packet.getTag() + ")"; } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedWorldChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedWorldChange.java index 711bd5d..c01e83a 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedWorldChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedWorldChange.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java index 08f1212..f8c77ce 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java @@ -15,12 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.PacketChangeEntity; import ru.windcorp.progressia.server.Server; @@ -36,7 +37,7 @@ class ChangeEntity extends CachedChange { super(disposer); } - public void set(T entity, StateChange change) { + public void set(EntityData entity, StateChange change) { if (this.entity != null) throw new IllegalStateException("Entity is not null. Current: " + this.entity + "; requested: " + entity); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/RemoveTile.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/RemoveTile.java index 42dea30..0f811b1 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/RemoveTile.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/RemoveTile.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/SetBlock.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/SetBlock.java index 330333b..e4cc4fb 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/SetBlock.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/SetBlock.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java index c0895e1..a2a59f9 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.ArrayList; @@ -27,83 +27,87 @@ import com.google.common.collect.ImmutableList; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.FloatMathUtil; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.tile.TileDataStack; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.ChunkLogic; -import ru.windcorp.progressia.server.world.TickContextMutable; +import ru.windcorp.progressia.server.world.DefaultChunkLogic; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.TickableBlock; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerContexts; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileStackContext; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; import ru.windcorp.progressia.server.world.ticking.Evaluation; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; -import ru.windcorp.progressia.server.world.tile.TSTickContext; import ru.windcorp.progressia.server.world.tile.TickableTile; import ru.windcorp.progressia.server.world.tile.TileLogic; -import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; +import static ru.windcorp.progressia.common.world.DefaultChunkData.BLOCKS_PER_CHUNK; public class TickChunk extends Evaluation { - private static final int CHUNK_VOLUME = ChunkData.BLOCKS_PER_CHUNK * - ChunkData.BLOCKS_PER_CHUNK * - ChunkData.BLOCKS_PER_CHUNK; + private static final int CHUNK_VOLUME = DefaultChunkData.BLOCKS_PER_CHUNK * + DefaultChunkData.BLOCKS_PER_CHUNK * + DefaultChunkData.BLOCKS_PER_CHUNK; - private final List> randomTickMethods; + private final List> randomTickMethods; { - List> randomTickMethods = new ArrayList<>(); + List> randomTickMethods = new ArrayList<>(); randomTickMethods.add(this::tickRandomBlock); - for (BlockFace face : BlockFace.getFaces()) { - randomTickMethods.add(s -> this.tickRandomTile(s, face)); + for (AbsFace face : AbsFace.getFaces()) { + randomTickMethods.add(context -> this.tickRandomTile(face, context)); } this.randomTickMethods = ImmutableList.copyOf(randomTickMethods); } - private final ChunkLogic chunk; + private final DefaultChunkLogic chunk; + private ServerWorldContext context; - public TickChunk(ChunkLogic chunk) { + public TickChunk(DefaultChunkLogic chunk) { this.chunk = chunk; } @Override public void evaluate(Server server) { - tickRegulars(server); - tickRandom(server); + if (context == null || context.getServer() != server) { + context = server.createContext(chunk.getUp()); + } + + tickRegulars(context); + tickRandom(context); } - private void tickRegulars(Server server) { - tickRegularBlocks(server); - tickRegularTiles(server); + private void tickRegulars(ServerWorldContext context) { + tickRegularBlocks(context); + tickRegularTiles(context); } - private void tickRegularBlocks(Server server) { + private void tickRegularBlocks(ServerWorldContext context) { if (!chunk.hasTickingBlocks()) return; - TickContextMutable context = TickContextMutable.uninitialized(); - chunk.forEachTickingBlock((blockInChunk, block) -> { - context.rebuild().withChunk(chunk).withBlockInChunk(blockInChunk).build(); - ((TickableBlock) block).tick(context); + ((TickableBlock) block).tick(ServerContexts.pushAbs(context, chunk, blockInChunk)); + context.pop(); }); } - private void tickRegularTiles(Server server) { + private void tickRegularTiles(ServerWorldContext context) { if (!chunk.hasTickingTiles()) return; - TickContextMutable context = TickContextMutable.uninitialized(); - chunk.forEachTickingTile((ref, tile) -> { - context.rebuild().withServer(server).withTile(ref); - ((TickableTile) tile).tick(context); + ((TickableTile) tile).tick(ServerContexts.pushAbs(context, chunk.getUp(), ref)); + context.pop(); }); } - private void tickRandom(Server server) { - float ticks = computeRandomTicks(server); + private void tickRandom(ServerWorldContext context) { + float ticks = computeRandomTicks(context.getServer()); /* * If we are expected to run 3.25 random ticks per tick @@ -114,23 +118,23 @@ public class TickChunk extends Evaluation { float extraTickChance = ticks - unconditionalTicks; for (int i = 0; i < unconditionalTicks; ++i) { - tickRandomOnce(server); + tickRandomOnce(context); } - if (server.getAdHocRandom().nextFloat() < extraTickChance) { - tickRandomOnce(server); + if (context.getRandom().nextFloat() < extraTickChance) { + tickRandomOnce(context); } } - private void tickRandomOnce(Server server) { + private void tickRandomOnce(ServerWorldContext context) { // Pick a target at random: a block or one of 3 primary block faces randomTickMethods.get( - server.getAdHocRandom().nextInt(randomTickMethods.size()) - ).accept(server); + context.getRandom().nextInt(randomTickMethods.size()) + ).accept(context); } - private void tickRandomBlock(Server server) { - Random random = server.getAdHocRandom(); + private void tickRandomBlock(ServerWorldContext context) { + Random random = context.getRandom(); Vec3i blockInChunk = new Vec3i( random.nextInt(BLOCKS_PER_CHUNK), @@ -144,15 +148,17 @@ public class TickChunk extends Evaluation { return; TickableBlock tickable = (TickableBlock) block; - TickContextMutable context = TickContextMutable.start().withChunk(chunk).withBlockInChunk(blockInChunk).build(); + ServerBlockContext blockContext = ServerContexts.pushAbs(context, chunk, blockInChunk); - if (tickable.getTickingPolicy(context) != TickingPolicy.RANDOM) + if (tickable.getTickingPolicy(blockContext) != TickingPolicy.RANDOM) return; - tickable.tick(context); + tickable.tick(blockContext); + + blockContext.pop(); } - private void tickRandomTile(Server server, BlockFace face) { - Random random = server.getAdHocRandom(); + private void tickRandomTile(AbsFace face, ServerWorldContext context) { + Random random = context.getRandom(); Vec3i blockInChunk = new Vec3i( random.nextInt(BLOCKS_PER_CHUNK), @@ -164,18 +170,28 @@ public class TickChunk extends Evaluation { if (tiles == null || tiles.isEmpty()) return; - TSTickContext context = TickContextMutable.start().withServer(server).withTS(tiles).build(); + ServerTileStackContext tsContext = ServerContexts.pushAbs(context, chunk, blockInChunk, face); - context.forEachTile(tctxt -> { - TileLogic logic = tctxt.getTile(); - if (!(logic instanceof TickableTile)) - return; + for (int i = 0; i < tiles.size(); ++i) { + ServerTileContext tileContext = tsContext.push(i); + + TileLogic logic = tileContext.logic().getTile(); + if (!(logic instanceof TickableTile)) { + tileContext.pop(); + continue; + } TickableTile tickable = (TickableTile) logic; - if (tickable.getTickingPolicy(tctxt) != TickingPolicy.RANDOM) - return; - tickable.tick(tctxt); - }); + if (tickable.getTickingPolicy(tileContext) != TickingPolicy.RANDOM) { + tileContext.pop(); + continue; + } + tickable.tick(tileContext); + + tileContext.pop(); + } + + tsContext.pop(); } private float computeRandomTicks(Server server) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickEntitiesTask.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickEntitiesTask.java index 1e76b23..8376c8d 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickEntitiesTask.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickEntitiesTask.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import glm.vec._3.i.Vec3i; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java index 76fc414..3635250 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java @@ -15,22 +15,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.TickAndUpdateUtil; -import ru.windcorp.progressia.server.world.WorldLogic; class TileTriggeredUpdate extends CachedEvaluation { private final Vec3i blockInWorld = new Vec3i(); - private BlockFace face = null; + private AbsFace face = null; public TileTriggeredUpdate(Consumer disposer) { super(disposer); @@ -40,20 +39,18 @@ class TileTriggeredUpdate extends CachedEvaluation { public void evaluate(Server server) { Vec3i cursor = new Vec3i(blockInWorld.x, blockInWorld.y, blockInWorld.z); - WorldLogic world = server.getWorld(); - - TickAndUpdateUtil.updateTiles(world, cursor, face); // Update facemates - // (also self) - TickAndUpdateUtil.updateBlock(world, cursor); // Update block on one - // side + // Update facemates (also self) + TickAndUpdateUtil.updateTiles(server, cursor, face); + // Update block on one side + TickAndUpdateUtil.updateBlock(server, cursor); cursor.add(face.getVector()); - TickAndUpdateUtil.updateBlock(world, cursor); // Update block on the - // other side - TickAndUpdateUtil.updateTiles(world, cursor, face.getCounter()); // Update - // complement + // Update block on the other side + TickAndUpdateUtil.updateBlock(server, cursor); + // Update complement + TickAndUpdateUtil.updateTiles(server, cursor, face.getCounter()); } - public void init(Vec3i blockInWorld, BlockFace face) { + public void init(Vec3i blockInWorld, AbsFace face) { this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); this.face = face; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java index 2c83ccd..76ab835 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java @@ -21,17 +21,21 @@ package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; import ru.windcorp.progressia.common.util.MultiLOC; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.block.BlockFace; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataRegistry; import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.context.impl.ReportingServerContext; import ru.windcorp.progressia.server.world.ticking.TickerTask; -public class WorldAccessor { +public class WorldAccessor implements ReportingServerContext.ChangeListener { private final MultiLOC cache; { @@ -54,43 +58,58 @@ public class WorldAccessor { this.server = server; } - public void setBlock(Vec3i blockInWorld, BlockData block) { + @Override + public void onBlockSet(Vec3i blockInWorld, BlockData block) { SetBlock change = cache.grab(SetBlock.class); change.getPacket().set(block, blockInWorld); server.requestChange(change); } - public void setBlock(Vec3i blockInWorld, String id) { - setBlock(blockInWorld, BlockDataRegistry.getInstance().get(id)); - } - - public void addTile(Vec3i blockInWorld, BlockFace face, TileData tile) { + @Override + public void onTileAdded(Vec3i blockInWorld, RelFace face, TileData tile) { AddTile change = cache.grab(AddTile.class); - change.getPacket().set(tile, blockInWorld, face); + change.getPacket().set(tile, blockInWorld, face.resolve(AbsFace.POS_Z)); server.requestChange(change); } - public void addTile(Vec3i blockInWorld, BlockFace face, String id) { - addTile(blockInWorld, face, TileDataRegistry.getInstance().get(id)); - } - - public void removeTile(Vec3i blockInWorld, BlockFace face, int tag) { + @Override + public void onTileRemoved(Vec3i blockInWorld, RelFace face, int tag) { RemoveTile change = cache.grab(RemoveTile.class); - change.getPacket().set(blockInWorld, face, tag); + change.getPacket().set(blockInWorld, face.resolve(AbsFace.POS_Z), tag); server.requestChange(change); } + + @Override + public void onEntityAdded(EntityData entity) { + // TODO Auto-generated method stub + + } + + @Override + public void onEntityRemoved(long entityId) { + // TODO Auto-generated method stub + + } + + @Override + public void onTimeChanged(float change) { + // TODO Auto-generated method stub + System.err.println("WorldAccessor.onTimeChanged() NYI!"); + } - public void changeEntity( - T entity, - StateChange stateChange + @Override + public void onEntityChanged( + SE entity, + StateChange stateChange ) { ChangeEntity change = cache.grab(ChangeEntity.class); - change.set(entity, stateChange); + change.set((EntityData) entity, stateChange); server.requestChange(change); } public void tickBlock(Vec3i blockInWorld) { // TODO + System.err.println("WorldAccessor.tickBlock(Vec3i) NYI!"); } /** @@ -114,7 +133,7 @@ public class WorldAccessor { // TODO rename to something meaningful public void triggerUpdates(Vec3i blockInWorld, BlockFace face) { TileTriggeredUpdate evaluation = cache.grab(TileTriggeredUpdate.class); - evaluation.init(blockInWorld, face); + evaluation.init(blockInWorld, face.resolve(AbsFace.POS_Z)); server.requestEvaluation(evaluation); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/Change.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/Change.java index b0fc7f2..c0cf115 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/Change.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/Change.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.ticking; import ru.windcorp.progressia.server.Server; @@ -32,14 +32,13 @@ public abstract class Change extends TickerTask { * Performs the changes on the provided server instance. *

    * This method will be executed when the world is in an inconsistent state - * and may not be queried, - * only changed. Therefore, all necessary inspection must be performed - * before this method is invoked, - * typically by an {@link Evaluation}. Failure to abide by this contract may - * lead to race conditions - * and/or devil invasions. + * and may not be queried, only changed. Therefore, all necessary inspection + * must be performed before this method is invoked, typically by an + * {@link Evaluation}. Failure to abide by this contract may lead to race + * conditions and/or devil invasions. * - * @param server the {@link Server} instance to affect + * @param server + * the {@link Server} instance to affect */ public abstract void affect(Server server); diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/DevilInvasionException.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/DevilInvasionException.java index 50ff69c..fd146bc 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/DevilInvasionException.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/DevilInvasionException.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.ticking; public class DevilInvasionException extends RuntimeException { diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/Evaluation.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/Evaluation.java index f4f3922..b541871 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/Evaluation.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/Evaluation.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.ticking; import ru.windcorp.progressia.server.Server; @@ -30,14 +30,15 @@ public abstract class Evaluation extends TickerTask { /** * Performs the analysis of the provided server instance. *

    - * This method will be executed when the world is in an consistent state - * and may be queried for meaningful information. However, other - * evaluations may be happening concurrently, so any world modification - * is prohibited. Evaluations are expected to request {@link Change}s - * to interact with the world. Failure to abide by this contract may - * lead to race conditions and/or devil invasions. + * This method will be executed when the world is in an consistent state and + * may be queried for meaningful information. However, other evaluations may + * be happening concurrently, so any world modification is prohibited. + * Evaluations are expected to request {@link Change}s to interact with the + * world. Failure to abide by this contract may lead to race conditions + * and/or devil invasions. * - * @param server the server instance to inspect + * @param server + * the server instance to inspect */ public abstract void evaluate(Server server); diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/Ticker.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/Ticker.java index 5c4b83e..4d0a22a 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/Ticker.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/Ticker.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.ticking; import java.util.ArrayList; diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java index 7d58d6d..aaea0ea 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.ticking; import java.util.ArrayList; @@ -23,8 +23,8 @@ import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.HashSet; import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -34,19 +34,24 @@ import com.google.common.collect.ImmutableList; import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.ChunkDataListeners; import ru.windcorp.progressia.server.Server; /** * Central control point for serverside ticking. This class provides an - * interface to - * interact with Tickers. + * interface to interact with Tickers. * * @author javapony */ public class TickerCoordinator { + + public enum TickPhase { + SYNCHRONOUS, + EVALUATION, + CHANGE + } static final int INITIAL_QUEUE_SIZE = 1024; @@ -66,8 +71,7 @@ public class TickerCoordinator { /** * All tasks that must be {@linkplain TickerTask#dispose() disposed of} at - * the end of the current - * tick. This list must be empty when not in + * the end of the current tick. This list must be empty when not in * {@link #runPassStage(Collection, String)}. */ private final Collection toDispose = new ArrayList<>(INITIAL_QUEUE_SIZE); @@ -77,7 +81,7 @@ public class TickerCoordinator { private final AtomicInteger workingTickers = new AtomicInteger(); - private final AtomicBoolean canChange = new AtomicBoolean(true); + private final AtomicReference phase = new AtomicReference<>(TickPhase.SYNCHRONOUS); private boolean isTickStartSet = false; private long tickStart = -1; @@ -96,17 +100,14 @@ public class TickerCoordinator { } this.tickers = ImmutableList.copyOf(tickerCollection); - this.threads = Collections2.transform(this.tickers, Ticker::getThread); // Immutable - // because - // it - // is - // a - // view + + // Immutable because it is a view + this.threads = Collections2.transform(this.tickers, Ticker::getThread); server.getWorld().getData().addListener(ChunkDataListeners.createAdder(new ChunkDataListener() { @Override - public void onChunkChanged(ChunkData chunk) { - if (!canChange.get()) { + public void onChunkChanged(DefaultChunkData chunk) { + if (phase.get() == TickPhase.EVALUATION) { throw CrashReports.report(null, "A change has been detected during evaluation phase"); } } @@ -152,12 +153,18 @@ public class TickerCoordinator { public double getTPS() { return 1 / tickLength; } - + public long getUptimeTicks() { return ticks; } + + public TickPhase getPhase() { + return phase.get(); + } private void onTickStart() { + phase.set(TickPhase.EVALUATION); + long now = System.currentTimeMillis(); if (isTickStartSet) { @@ -168,9 +175,10 @@ public class TickerCoordinator { tickStart = System.currentTimeMillis(); } - + private void onTickEnd() { ticks++; + phase.set(TickPhase.SYNCHRONOUS); } /* @@ -191,7 +199,7 @@ public class TickerCoordinator { logger.debug("Pass complete"); passes++; } - + onTickEnd(); logger.debug("Tick complete; run {} passes", passes); @@ -212,17 +220,14 @@ public class TickerCoordinator { } private synchronized void runOnePass() throws InterruptedException { - canChange.set(false); + phase.set(TickPhase.EVALUATION); runPassStage(pendingEvaluations, "EVALUATION"); - canChange.set(true); + phase.set(TickPhase.CHANGE); runPassStage(pendingChanges, "CHANGE"); } - private synchronized void runPassStage( - Collection tasks, - String stageName - ) - throws InterruptedException { + private synchronized void runPassStage(Collection tasks, String stageName) + throws InterruptedException { if (!toDispose.isEmpty()) throw new IllegalStateException("toDispose is not empty: " + toDispose); @@ -238,11 +243,8 @@ public class TickerCoordinator { toDispose.clear(); } - private synchronized void startPassStage( - Collection tasks, - Collection toDispose, - String stageName - ) { + private synchronized void startPassStage(Collection tasks, Collection toDispose, + String stageName) { if (tasks.isEmpty()) { logger.debug("Skipping stage {}: tasks is empty", stageName); return; @@ -269,11 +271,8 @@ public class TickerCoordinator { logger.debug("Stage started"); } - private Collection selectTasks( - Ticker ticker, - Collection tasks, - Collection output - ) { + private Collection selectTasks(Ticker ticker, Collection tasks, + Collection output) { // TODO implement properly for (TickerTask task : tasks) { @@ -319,12 +318,8 @@ public class TickerCoordinator { logger.debug("javahorse kill urself"); } - throw CrashReports.crash( - t, - "Something has gone horribly wrong in server ticker code " - + "(thread %s) and it is (probably) not related to mods or devils.", - thread - ); + throw CrashReports.crash(t, "Something has gone horribly wrong in server ticker code " + + "(thread %s) and it is (probably) not related to mods or devils.", thread); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerTask.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerTask.java index 4a075c0..a5f9738 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerTask.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerTask.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.ticking; import glm.vec._3.i.Vec3i; @@ -23,11 +23,10 @@ import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.server.Server; /** - * A task that can be executed by a Ticker. - * This is a superinterface for {@link Change} and {@link Evaluation} and is not - * meant to be extended further. - * This interface is used to determine the Ticker that is suitable for the - * execution of this task. + * A task that can be executed by a Ticker. This is a superinterface for + * {@link Change} and {@link Evaluation} and is not meant to be extended + * further. This interface is used to determine the Ticker that is suitable for + * the execution of this task. * * @author javapony */ @@ -35,8 +34,8 @@ public abstract class TickerTask { /** * Returns {@code false} iff this task is thread-safe and may be executed by - * any Ticker. If and only if a task returns {@code true} in this method - * is its {@link #getRelevantChunk(Vec3i)} method invoked. + * any Ticker. If and only if a task returns {@code true} in this method is + * its {@link #getRelevantChunk(Vec3i)} method invoked. * * @implNote Default implementation returns {@code true}, making this task * thread-sensitive @@ -49,18 +48,18 @@ public abstract class TickerTask { /** * Sets {@code output} to be equal to the {@linkplain Coordinates#chunk - * coordinates of chunk} - * of the chunk that must be owned by the Ticker will execute this task. - * This method - * is not invoked iff {@link #isThreadSensitive()} returned {@code false}. + * coordinates of chunk} of the chunk that must be owned by the Ticker will + * execute this task. This method is not invoked iff + * {@link #isThreadSensitive()} returned {@code false}. * - * @param output a {@link Vec3i} to set to the requested value + * @param output + * a {@link Vec3i} to set to the requested value */ public abstract void getRelevantChunk(Vec3i output); /** - * Invoked when this task has completed and will no longer be used. - * This method is guaranteed to be invoked in the main server thread. + * Invoked when this task has completed and will no longer be used. This + * method is guaranteed to be invoked in the main server thread. * * @implNote Default implementation does nothing */ @@ -72,7 +71,8 @@ public abstract class TickerTask { * Executes this task. This method is provided for the convenience of * Tickers. * - * @param server the server to run on + * @param server + * the server to run on */ abstract void run(Server server); diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickingPolicy.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickingPolicy.java index a5836fe..87a6fc9 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickingPolicy.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickingPolicy.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.ticking; import ru.windcorp.progressia.server.world.block.TickableBlock; @@ -23,27 +23,24 @@ import ru.windcorp.progressia.server.world.tile.TickableTile; /** * Various ticking policies that {@link TickableBlock} or {@link TickableTile} - * can have. - * Ticking policy determines when, and if, the block or tile is ticked. + * can have. Ticking policy determines when, and if, the block or tile is + * ticked. * * @author javapony */ public enum TickingPolicy { /** - * The ticking policy that requests that no ticks happen. - * This is typically used for blocks or tiles that only tick under certain - * conditions, - * which are not meant at the moment. + * The ticking policy that requests that no ticks happen. This is typically + * used for blocks or tiles that only tick under certain conditions, which + * are not meant at the moment. */ NONE, /** * The ticking policy that requests that the object is ticked every server - * tick exactly once. - * This should not be used for objects that only change rarely; consider - * using {@link RANDOM} - * instead. + * tick exactly once. This should not be used for objects that only change + * rarely; consider using {@link RANDOM} instead. */ REGULAR, diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java index 745f289..55f8ec7 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java @@ -15,10 +15,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; public class HangingTileLogic extends TileLogic implements UpdateableTile { @@ -27,15 +29,15 @@ public class HangingTileLogic extends TileLogic implements UpdateableTile { } @Override - public void update(TileTickContext context) { + public void update(ServerTileContext context) { if (!canOccupyFace(context)) { - context.removeThisTile(); + context.removeTile(); } } @Override - public boolean canOccupyFace(TileTickContext context) { - BlockLogic host = context.getBlock(); + public boolean canOccupyFace(ServerTileContextRO context) { + BlockLogic host = context.logic().getBlock(); if (host == null) return false; @@ -45,13 +47,12 @@ public class HangingTileLogic extends TileLogic implements UpdateableTile { if (canBeSquashed(context)) return true; - return context.evalComplementary(ctxt -> { - BlockLogic complHost = ctxt.getBlock(); - return complHost == null || !complHost.isSolid(ctxt, context.getFace()); - }); + context.pushOpposite(); + BlockLogic complHost = context.logic().getBlock(); + return context.popAndReturn(complHost == null || !complHost.isSolid(context, context.getFace())); } - public boolean canBeSquashed(TileTickContext context) { + public boolean canBeSquashed(ServerTileContextRO context) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java deleted file mode 100644 index 399f7b8..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.server.world.tile; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Function; - -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.server.world.ChunkLogic; -import ru.windcorp.progressia.server.world.TickContextMutable; -import ru.windcorp.progressia.server.world.block.BlockTickContext; - -public interface TSTickContext extends BlockTickContext { - - /* - * Specifications - */ - - BlockFace getFace(); - - /* - * Getters - */ - - default TileLogicStack getTLSOrNull() { - ChunkLogic chunkLogic = getChunkLogic(); - if (chunkLogic == null) - return null; - - return chunkLogic.getTilesOrNull(getBlockInChunk(), getFace()); - } - - default TileLogicStack getTLS() { - return getChunkLogic().getTiles(getBlockInChunk(), getFace()); - } - - default TileDataStack getTDSOrNull() { - ChunkData chunkData = getChunkData(); - if (chunkData == null) - return null; - - return chunkData.getTilesOrNull(getBlockInChunk(), getFace()); - } - - default TileDataStack getTDS() { - return getChunkData().getTiles(getBlockInChunk(), getFace()); - } - - /* - * Contexts - */ - - default TileTickContext forLayer(int layer) { - return TickContextMutable.start().withServer(getServer()).withBlock(getBlockInWorld()).withFace(getFace()) - .withLayer(layer); - } - - default boolean forEachTile(Consumer action) { - TickContextMutable context = TickContextMutable.uninitialized(); - - TileDataStack stack = getTDSOrNull(); - if (stack == null || stack.isEmpty()) - return false; - - for (int layer = 0; layer < stack.size(); ++layer) { - context.rebuild().withServer(getServer()).withBlock(getBlockInWorld()).withFace(getFace()).withLayer(layer); - action.accept(context); - } - - return true; - } - - default TSTickContext getComplementary() { - return TickContextMutable.copyWorld(this) - .withBlock(getBlockInWorld().add_(getFace().getVector())) - .withFace(getFace().getCounter()) - .build(); - } - - default R evalComplementary(Function action) { - Objects.requireNonNull(action, "action"); - return action.apply(getComplementary()); - } - - default void forComplementary(Consumer action) { - Objects.requireNonNull(action, "action"); - evalComplementary((Function) ctxt -> { - action.accept(ctxt); - return null; - }); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java index 4def3b0..60d2031 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java @@ -15,15 +15,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tile; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; public interface TickableTile { - void tick(TileTickContext context); + void tick(ServerTileContext context); - TickingPolicy getTickingPolicy(TileTickContext context); + TickingPolicy getTickingPolicy(ServerTileContextRO context); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java index 4a97ead..9a9ff8f 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java @@ -15,28 +15,29 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.generic.TileGeneric; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; -public class TileLogic extends Namespaced implements GenericTile { +public class TileLogic extends Namespaced implements TileGeneric { public TileLogic(String id) { super(id); } - public boolean canOccupyFace(TileTickContext context) { + public boolean canOccupyFace(ServerTileContextRO context) { return canOccupyFace(context.getFace()); } - public boolean canOccupyFace(BlockFace face) { + public boolean canOccupyFace(RelFace face) { return true; } - public boolean isSolid(TileTickContext context) { + public boolean isSolid(ServerTileContextRO context) { return isSolid(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicRegistry.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicRegistry.java index d8bceaf..cc0fca6 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicRegistry.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicRegistry.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java deleted file mode 100644 index 45f41ec..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.server.world.tile; - -import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileReference; - -public interface TileTickContext extends TSTickContext { - - /* - * Specifications - */ - - /** - * Returns the current layer. - * - * @return the layer that the tile being ticked occupies in the tile stack - */ - int getLayer(); - - /* - * Getters - */ - - default TileLogic getTile() { - TileLogicStack stack = getTLSOrNull(); - if (stack == null) - return null; - return stack.get(getLayer()); - } - - default TileData getTileData() { - TileDataStack stack = getTDSOrNull(); - if (stack == null) - return null; - return stack.get(getLayer()); - } - - default TileReference getReference() { - return getTDS().getReference(getLayer()); - } - - default int getTag() { - return getTDS().getTagByIndex(getLayer()); - } - - /* - * Contexts - */ - - /* - * Convenience methods - changes - */ - - default void removeThisTile() { - getAccessor().removeTile(getBlockInWorld(), getFace(), getTag()); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java b/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java index bf114fa..c1baadf 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java @@ -15,11 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tile; +import ru.windcorp.progressia.server.world.context.ServerTileContext; + public interface UpdateableTile { - void update(TileTickContext context); + void update(ServerTileContext context); } diff --git a/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java b/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java index 4c7ca68..345e7f8 100644 --- a/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java +++ b/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; import glm.mat._4.Mat4; @@ -33,9 +33,9 @@ import ru.windcorp.progressia.common.collision.CompoundCollisionModel; public class CollisionModelRenderer { private static final Shape CUBE = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null) - .setColorMultiplier(1.0f, 0.7f, 0.2f).create(); + .setColorMultiplier(1.0f, 0.7f, 0.2f).create(); private static final Shape CUBE_GRAY = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null) - .setColorMultiplier(0.5f, 0.5f, 0.5f).create(); + .setColorMultiplier(0.5f, 0.5f, 0.5f).create(); public static void renderCollisionModel(CollisionModel model, ShapeRenderHelper helper) { if (model instanceof AABBoid) { @@ -60,10 +60,7 @@ public class CollisionModelRenderer { helper.popTransform(); } - private static void renderCompound( - CompoundCollisionModel model, - ShapeRenderHelper helper - ) { + private static void renderCompound(CompoundCollisionModel model, ShapeRenderHelper helper) { for (CollisionModel part : model.getModels()) { renderCollisionModel(part, helper); } diff --git a/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java b/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java index a9df57a..d7e8a36 100644 --- a/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java +++ b/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; import glm.vec._3.i.Vec3i; diff --git a/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java b/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java index f3e45e2..f83a0cc 100644 --- a/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java +++ b/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; import glm.vec._3.i.Vec3i; diff --git a/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java b/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java index 5a37b6f..5fd8764 100644 --- a/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java +++ b/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java @@ -15,19 +15,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.comms.controls.ControlData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; public class ControlPlaceTileData extends ControlData { private TileData tile; private final Vec3i blockInWorld = new Vec3i(); - private BlockFace face; + private AbsFace face; public ControlPlaceTileData(String id) { super(id); @@ -41,11 +41,11 @@ public class ControlPlaceTileData extends ControlData { return blockInWorld; } - public BlockFace getFace() { + public AbsFace getFace() { return face; } - public void set(TileData block, Vec3i blockInWorld, BlockFace face) { + public void set(TileData block, Vec3i blockInWorld, AbsFace face) { this.tile = block; this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); this.face = face; diff --git a/src/main/java/ru/windcorp/progressia/test/DebugGraphics.java b/src/main/java/ru/windcorp/progressia/test/DebugGraphics.java new file mode 100644 index 0000000..859132f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/DebugGraphics.java @@ -0,0 +1,95 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test; + +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.client.graphics.model.Shapes; +import ru.windcorp.progressia.client.graphics.model.StaticModel; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; +import ru.windcorp.progressia.common.util.Vectors; + +public class DebugGraphics { + + private static final float TAIL_THICKNESS = 0.03f; + private static final float HEAD_SIZE = 0.1f; + + private static final Renderable THE_VECTOR = StaticModel.builder().addPart( + new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null) + .setSize(1.0f, TAIL_THICKNESS, TAIL_THICKNESS) + .setOrigin(0, -TAIL_THICKNESS / 2, -TAIL_THICKNESS / 2) + .create() + ).addPart( + new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null) + .setSize(HEAD_SIZE, HEAD_SIZE, HEAD_SIZE) + .setOrigin((1 - HEAD_SIZE / 2), -HEAD_SIZE / 2, -HEAD_SIZE / 2) + .create() + ).build(); + + public static void drawVector(Vec3 vector, Vec4 color, Vec3 origin, float scale, ShapeRenderHelper renderer) { + float length = vector.length(); + if (length == 0) return; + + if (scale == 0) scale = 1 / length; + + Mat4 mat = renderer.pushTransform(); + + mat.translate(origin); + + Vec3 somePerpendicular = new Vec3(); + + if (Math.abs(vector.z) > (1 - 1e-4f) * length) { + somePerpendicular.set(1, 0, 0); + } else { + somePerpendicular.set(0, 0, 1); + } + + Vec3 f = vector; + Vec3 s = somePerpendicular.cross_(f).normalize(); + Vec3 u = somePerpendicular.set(f).cross(s).normalize(); + + // @formatter:off + mat.mul(new Mat4( + +f.x * scale, +f.y * scale, +f.z * scale, 0, + -s.x, -s.y, -s.z, 0, + +u.x, +u.y, +u.z, 0, + 0, 0, 0, 1 + )); + // @formatter:on + + renderer.pushColorMultiplier().mul(color); + THE_VECTOR.render(renderer); + renderer.popColorMultiplier(); + + renderer.popTransform(); + } + + public static void drawVector(Vec3 vector, ShapeRenderHelper renderer) { + drawVector(vector, Colors.GRAY_A, Vectors.ZERO_3, 1, renderer); + } + + public static void drawDirection(Vec3 vector, ShapeRenderHelper renderer) { + drawVector(vector, Colors.GRAY_A, Vectors.ZERO_3, 0, renderer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/LayerAbout.java b/src/main/java/ru/windcorp/progressia/test/LayerAbout.java index 7b45fd4..334b462 100644 --- a/src/main/java/ru/windcorp/progressia/test/LayerAbout.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerAbout.java @@ -50,7 +50,7 @@ public class LayerAbout extends GUILayer { new Label( "Version", font, - new MutableStringLocalized("LayerAbout.Version").format("pre-alpha 1") + new MutableStringLocalized("LayerAbout.Version").format("pre-alpha 2") ) ); diff --git a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java index fb69ca3..65913d2 100755 --- a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java @@ -35,6 +35,7 @@ import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; import ru.windcorp.progressia.client.localization.Localizer; import ru.windcorp.progressia.client.localization.MutableString; import ru.windcorp.progressia.client.localization.MutableStringLocalized; +import ru.windcorp.progressia.client.world.WorldRender; import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.util.dynstr.DynamicStrings; import ru.windcorp.progressia.server.Server; @@ -84,17 +85,6 @@ public class LayerTestGUI extends GUILayer { ) ); - group.addChild( - new Label( - "GravityModeDisplay", - font, - tmp_dynFormat( - "LayerTestGUI.GravityModeDisplay", - () -> tpc.useMinecraftGravity() ? "Minecraft" : "Realistic" - ) - ) - ); - group.addChild( new Label( "LanguageDisplay", @@ -139,14 +129,37 @@ public class LayerTestGUI extends GUILayer { 128 ) ); - + group.addChild( new DynamicLabel( - "ChunkUpdatesDisplay", + "ChunkStatsDisplay", font, DynamicStrings.builder() - .addDyn(new MutableStringLocalized("LayerTestGUI.ChunkUpdatesDisplay")) - .addDyn(ClientState.getInstance().getWorld()::getPendingChunkUpdates) + .addDyn(new MutableStringLocalized("LayerTestGUI.ChunkStatsDisplay")) + .addDyn(() -> { + if (ClientState.getInstance() == null) { + return -1; + } else { + WorldRender world = ClientState.getInstance().getWorld(); + return world.getChunks().size() - world.getPendingChunkUpdates(); + } + }, 4) + .add('/') + .addDyn(() -> { + if (ClientState.getInstance() == null) { + return -1; + } else { + return ClientState.getInstance().getWorld().getPendingChunkUpdates(); + } + }, 4) + .add('/') + .addDyn(() -> { + if (ServerState.getInstance() == null) { + return -1; + } else { + return ServerState.getInstance().getWorld().getChunks().size(); + } + }, 4) .buildSupplier(), 128 ) diff --git a/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java b/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java index c93a055..19c10aa 100755 --- a/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java @@ -15,26 +15,20 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; import org.lwjgl.glfw.GLFW; import com.google.common.eventbus.Subscribe; -import glm.mat._4.Mat4; import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.flat.AssembledFlatLayer; import ru.windcorp.progressia.client.graphics.flat.RenderTarget; import ru.windcorp.progressia.client.graphics.input.KeyEvent; import ru.windcorp.progressia.client.graphics.input.bus.Input; -import ru.windcorp.progressia.client.graphics.model.LambdaModel; -import ru.windcorp.progressia.client.graphics.texture.SimpleTextures; -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.client.graphics.world.Camera; public class LayerTestUI extends AssembledFlatLayer { @@ -44,60 +38,13 @@ public class LayerTestUI extends AssembledFlatLayer { GraphicsInterface.subscribeToInputEvents(this); } - private boolean flag = false; - - private static final int WIDTH = 80; - private static final int HEIGHT = 80; - private static final int BORDER = 5; + private boolean drawUI = true; @Override protected void assemble(RenderTarget target) { - final int boxColor = flag ? 0xFFEE8888 : 0xFFEEEE88; - final int borderColor = flag ? 0xFFAA4444 : 0xFFAAAA44; - final int boxShadowColor = flag ? 0xFF440000 : 0xFF444400; - - int x = 2 * BORDER; - int y = 2 * BORDER; - - target.fill(x + BORDER, y - BORDER, WIDTH, HEIGHT, boxShadowColor); - target.fill(x - 1, y - 1, WIDTH + 2, HEIGHT + 2, boxShadowColor); - target.fill(x, y, WIDTH, HEIGHT, borderColor); - target.fill(x + BORDER, y + BORDER, WIDTH - 2 * BORDER, HEIGHT - 2 * BORDER, boxColor); - - final int texShadow = 2; - final int texSize = HEIGHT - 4 * BORDER; - - target.pushTransform(new Mat4().identity().translate(x + 2 * BORDER, y + 2 * BORDER, 0)); - - final Texture compassBg = SimpleTextures.get("compass_icon"); - final Texture compassFg = SimpleTextures.get("compass_icon_arrow"); - - target.drawTexture(texShadow, -texShadow, texSize, texSize, Colors.BLACK, compassBg); - target.drawTexture(0, 0, texSize, texSize, compassBg); - - target.addCustomRenderer( - new LambdaModel( - LambdaModel.lambdaBuilder() - .addDynamicPart( - target.createRectagle(0, 0, texSize, texSize, Colors.WHITE, compassFg), - mat -> mat.translate(texSize / 2, texSize / 2, 0) - .rotateZ(getCompassRotation()) - .translate(-texSize / 2, -texSize / 2, 0) - ) - ) - ); - target.popTransform(); - - drawCross(target); - } - - private double getCompassRotation() { - Camera.Anchor anchor = ClientState.getInstance().getCamera().getAnchor(); - - if (anchor == null) - return 0; - - return -anchor.getCameraYaw(); + if (drawUI) { + drawCross(target); + } } private void drawCross(RenderTarget target) { @@ -145,16 +92,16 @@ public class LayerTestUI extends AssembledFlatLayer { @Override protected void handleInput(Input input) { - + // Do nothing } @Subscribe public void onKeyEvent(KeyEvent event) { - if (event.isRepeat() || event.getKey() != GLFW.GLFW_KEY_LEFT_CONTROL) { + if (!event.isPress() || event.getKey() != GLFW.GLFW_KEY_F1) { return; } - flag = event.isPress(); + drawUI = !drawUI; invalidate(); } diff --git a/src/main/java/ru/windcorp/progressia/test/Rocks.java b/src/main/java/ru/windcorp/progressia/test/Rocks.java new file mode 100644 index 0000000..ebf31fe --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/Rocks.java @@ -0,0 +1,126 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test; + +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; + +import ru.windcorp.progressia.client.world.block.BlockRenderOpaqueCube; +import ru.windcorp.progressia.client.world.block.BlockRenderRegistry; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; + +public class Rocks { + + public enum RockType { + IGNEOUS, METAMORPHIC, SEDIMENTARY; + } + + public enum RockVariant { + + MONOLITH("Monolith"), + CRACKED("Cracked"), + GRAVEL("Gravel"), + SAND("Sand"); + + private final String name; + + private RockVariant(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + } + + public static class Rock { + + private final String name; + private final RockType type; + + private final Map blocks = new EnumMap<>(RockVariant.class); + + public Rock(String name, RockType type) { + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + + public RockType getType() { + return type; + } + + public BlockData getBlock(RockVariant variant) { + return blocks.get(variant); + } + + private void register() { + for (RockVariant variant : RockVariant.values()) { + + String fullName = name + variant.getName(); + String id = "Test:" + fullName; + + BlockData blockData = new BlockData(id); + blocks.put(variant, blockData); + BlockDataRegistry.getInstance().register(blockData); + BlockLogicRegistry.getInstance().register(new BlockLogic(id)); + BlockRenderRegistry.getInstance() + .register(new BlockRenderOpaqueCube(id, BlockRenderRegistry.getBlockTexture(fullName))); + + } + } + + } + + private final Map rocksByName = Collections.synchronizedMap(new HashMap<>()); + private final Multimap rocksByType = Multimaps.synchronizedMultimap(HashMultimap.create()); + + public Rock create(RockType type, String name) { + Rock rock = new Rock(name, type); + rocksByName.put(name, rock); + rocksByType.put(type, rock); + return rock; + } + + public void registerAllRocks() { + getRocks().forEach(Rock::register); + } + + public Collection getRocks() { + return rocksByName.values(); + } + + public Collection getRocks(RockType type) { + return rocksByType.get(type); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java index e378dbf..d18f850 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java @@ -15,10 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; public class TestBlockLogicAir extends BlockLogic { @@ -28,7 +28,7 @@ public class TestBlockLogicAir extends BlockLogic { } @Override - public boolean isSolid(BlockFace face) { + public boolean isSolid(RelFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java index eca9e5c..f2603cc 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java @@ -15,10 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; public class TestBlockLogicGlass extends BlockLogic { @@ -28,7 +28,7 @@ public class TestBlockLogicGlass extends BlockLogic { } @Override - public boolean isSolid(BlockFace face) { + public boolean isSolid(RelFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java index a4f891b..f4e81c5 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java @@ -33,13 +33,14 @@ import gnu.trove.map.TObjectIntMap; import gnu.trove.map.hash.TObjectIntHashMap; import ru.windcorp.jputil.functions.ThrowingConsumer; import ru.windcorp.progressia.common.state.IOContext; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.common.world.io.ChunkCodec; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; @@ -75,7 +76,7 @@ public class TestChunkCodec extends ChunkCodec { } @Override - public boolean shouldEncode(ChunkData chunk, IOContext context) { + public boolean shouldEncode(DefaultChunkData chunk, IOContext context) { return true; } @@ -84,13 +85,14 @@ public class TestChunkCodec extends ChunkCodec { */ @Override - public ChunkData decode(WorldData world, Vec3i position, DataInputStream input, IOContext context) + public DefaultChunkData decode(DefaultWorldData world, Vec3i position, DataInputStream input, IOContext context) throws DecodingException, IOException { BlockData[] blockPalette = readBlockPalette(input); TileData[] tilePalette = readTilePalette(input); - ChunkData chunk = new ChunkData(position, world); + DefaultChunkData chunk = new DefaultChunkData(position, world); + readBlocks(input, blockPalette, chunk); readTiles(input, tilePalette, chunk); @@ -119,9 +121,9 @@ public class TestChunkCodec extends ChunkCodec { return palette; } - private void readBlocks(DataInput input, BlockData[] blockPalette, ChunkData chunk) throws IOException { + private void readBlocks(DataInput input, BlockData[] blockPalette, DefaultChunkData chunk) throws IOException { try { - chunk.forEachBiC(guard(v -> { + GenericChunks.forEachBiC(guard(v -> { chunk.setBlock(v, blockPalette[input.readInt()], false); })); } catch (UncheckedIOException e) { @@ -129,7 +131,7 @@ public class TestChunkCodec extends ChunkCodec { } } - private void readTiles(DataInput input, TileData[] tilePalette, ChunkData chunk) throws IOException { + private void readTiles(DataInput input, TileData[] tilePalette, DefaultChunkData chunk) throws IOException { Vec3i bic = new Vec3i(); while (true) { @@ -138,7 +140,7 @@ public class TestChunkCodec extends ChunkCodec { break; bic.set(xOrEndMarker, input.readByte() & 0xFF, input.readByte() & 0xFF); - BlockFace face = BlockFace.getFaces().get(input.readByte() & 0xFF); + RelFace face = RelFace.getFaces().get(input.readByte() & 0xFF); int tiles = input.readByte() & 0xFF; @@ -155,7 +157,7 @@ public class TestChunkCodec extends ChunkCodec { */ @Override - public void encode(ChunkData chunk, DataOutputStream output, IOContext context) throws IOException { + public void encode(DefaultChunkData chunk, DataOutputStream output, IOContext context) throws IOException { Palette blockPalette = createBlockPalette(chunk); Palette tilePalette = createTilePalette(chunk); @@ -166,13 +168,13 @@ public class TestChunkCodec extends ChunkCodec { writeTiles(chunk, tilePalette, output); } - private Palette createBlockPalette(ChunkData chunk) { + private Palette createBlockPalette(DefaultChunkData chunk) { Palette blockPalette = new Palette<>(); - chunk.forEachBiC(v -> blockPalette.add(chunk.getBlock(v))); + GenericChunks.forEachBiC(v -> blockPalette.add(chunk.getBlock(v))); return blockPalette; } - private Palette createTilePalette(ChunkData chunk) { + private Palette createTilePalette(DefaultChunkData chunk) { Palette tilePalette = new Palette<>(); chunk.forEachTile((ts, t) -> tilePalette.add(t)); return tilePalette; @@ -194,9 +196,9 @@ public class TestChunkCodec extends ChunkCodec { } } - private void writeBlocks(ChunkData chunk, Palette blockPalette, DataOutput output) throws IOException { + private void writeBlocks(DefaultChunkData chunk, Palette blockPalette, DataOutput output) throws IOException { try { - chunk.forEachBiC(guard(v -> { + GenericChunks.forEachBiC(guard(v -> { output.writeInt(blockPalette.getNid(chunk.getBlock(v))); })); } catch (UncheckedIOException e) { @@ -204,7 +206,7 @@ public class TestChunkCodec extends ChunkCodec { } } - private void writeTiles(ChunkData chunk, Palette tilePalette, DataOutput output) throws IOException { + private void writeTiles(DefaultChunkData chunk, Palette tilePalette, DataOutput output) throws IOException { Vec3i bic = new Vec3i(); try { diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index dad5496..99c41fc 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -27,10 +27,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; - import org.lwjgl.glfw.GLFW; -import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.audio.Sound; @@ -47,25 +45,31 @@ import ru.windcorp.progressia.common.collision.AABB; import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.comms.controls.*; import ru.windcorp.progressia.common.state.StatefulObjectRegistry.Factory; +import ru.windcorp.progressia.common.world.GravityModelRegistry; import ru.windcorp.progressia.common.world.block.*; import ru.windcorp.progressia.common.world.entity.*; import ru.windcorp.progressia.common.world.io.ChunkIO; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.*; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.comms.controls.*; import ru.windcorp.progressia.server.world.block.*; import ru.windcorp.progressia.server.world.entity.*; +import ru.windcorp.progressia.server.world.generation.planet.PlanetGravityModel; import ru.windcorp.progressia.server.world.tile.*; +import ru.windcorp.progressia.test.Rocks.RockType; +import ru.windcorp.progressia.test.gen.TestGravityModel; public class TestContent { public static final String PLAYER_LOGIN = "Sasha"; public static final long PLAYER_ENTITY_ID = 0x42; public static final long STATIE_ENTITY_ID = 0xDEADBEEF; - public static final Vec3 SPAWN = new Vec3(8, 8, 880); public static final List PLACEABLE_BLOCKS = new ArrayList<>(); public static final List PLACEABLE_TILES = new ArrayList<>(); + + public static final Rocks ROCKS = new Rocks(); public static void registerContent() { registerWorldContent(); @@ -100,13 +104,7 @@ public class TestContent { register(new BlockRenderOpaqueCube("Test:Stone", getBlockTexture("Stone"))); register(new BlockLogic("Test:Stone")); - for (String type : new String[] { "Monolith", "Cracked", "Gravel" }) { - String id = "Test:Granite" + type; - - register(new BlockData(id)); - register(new BlockRenderOpaqueCube(id, getBlockTexture("Granite" + type))); - register(new BlockLogic(id)); - } + registerRocks(); register(new BlockData("Test:Brick")); register(new BlockRenderOpaqueCube("Test:Brick", getBlockTexture("Brick"))); @@ -134,13 +132,13 @@ public class TestContent { "Test:Log", getBlockTexture("LogTop"), getBlockTexture("LogTop"), - getBlockTexture("LogSide"), - getBlockTexture("LogSide"), - getBlockTexture("LogSide"), getBlockTexture("LogSide") ) ); register(new BlockLogic("Test:Log")); + register(new BlockData("Test:TemporaryLeaves")); + register(new BlockRenderTransparentCube("Test:TemporaryLeaves", getBlockTexture("TemporaryLeaves"))); + register(new TestBlockLogicGlass("Test:TemporaryLeaves")); // Sic, using Glass logic for leaves because Test register(new BlockData("Test:WoodenPlank")); register(new BlockRenderOpaqueCube("Test:WoodenPlank", getBlockTexture("WoodenPlank"))); @@ -152,11 +150,24 @@ public class TestContent { } + private static void registerRocks() { + + ROCKS.create(RockType.IGNEOUS, "BlackGranite"); + ROCKS.create(RockType.IGNEOUS, "RedGranite"); + ROCKS.create(RockType.IGNEOUS, "Gabbro"); + ROCKS.create(RockType.METAMORPHIC, "Marble"); + ROCKS.create(RockType.METAMORPHIC, "Eclogite"); + ROCKS.create(RockType.SEDIMENTARY, "Limestone"); + ROCKS.create(RockType.SEDIMENTARY, "Dolomite"); + + ROCKS.registerAllRocks(); + } + private static void registerTiles() { Set placeableBlacklist = new HashSet<>(); register(new TileData("Test:Grass")); - register(new TileRenderGrass("Test:Grass", getTileTexture("GrassTop"), getTileTexture("GrassSide"))); + register(new TestTileRenderGrass("Test:Grass", getTileTexture("GrassTop"), getTileTexture("GrassSide"))); register(new TestTileLogicGrass("Test:Grass")); register(new TileData("Test:Stones")); @@ -245,6 +256,10 @@ public class TestContent { register("Test:Statie", TestEntityDataStatie::new); register(new TestEntityRenderStatie("Test:Statie")); register(new TestEntityLogicStatie("Test:Statie")); + + register("Test:FallingBlock", TestEntityDataFallingBlock::new); + register(new TestEntityLogicFallingBlock("Test:FallingBlock")); + register(new TestEntityRenderFallingBlock("Test:FallingBlock")); } private static void regsiterControls() { @@ -381,7 +396,7 @@ public class TestContent { ru.windcorp.progressia.server.comms.Client client ) { Vec3i blockInWorld = ((ControlBreakBlockData) packet.getControl()).getBlockInWorld(); - server.getWorldAccessor().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air")); + server.createAbsoluteContext().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air")); } private static void onBlockPlaceTrigger(ControlData control) { @@ -401,7 +416,7 @@ public class TestContent { Vec3i blockInWorld = controlData.getBlockInWorld(); if (server.getWorld().getData().getChunkByBlock(blockInWorld) == null) return; - server.getWorldAccessor().setBlock(blockInWorld, block); + server.createAbsoluteContext().setBlock(blockInWorld, block); } private static void onTilePlaceTrigger(ControlData control) { @@ -420,18 +435,20 @@ public class TestContent { ControlPlaceTileData controlData = ((ControlPlaceTileData) packet.getControl()); TileData tile = controlData.getTile(); Vec3i blockInWorld = controlData.getBlockInWorld(); - BlockFace face = controlData.getFace(); + AbsFace face = controlData.getFace(); if (server.getWorld().getData().getChunkByBlock(blockInWorld) == null) return; if (server.getWorld().getData().getTiles(blockInWorld, face).isFull()) return; - server.getWorldAccessor().addTile(blockInWorld, face, tile); + server.createAbsoluteContext().addTile(blockInWorld, face.relativize(AbsFace.POS_Z), tile); } private static void registerMisc() { ChunkIO.registerCodec(new TestChunkCodec()); ChunkRenderOptimizerRegistry.getInstance().register("Core:SurfaceOptimizer", ChunkRenderOptimizerSurface::new); + GravityModelRegistry.getInstance().register("Test:TheGravityModel", TestGravityModel::new); + GravityModelRegistry.getInstance().register("Test:PlanetGravityModel", PlanetGravityModel::new); } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityDataFallingBlock.java b/src/main/java/ru/windcorp/progressia/test/TestEntityDataFallingBlock.java new file mode 100644 index 0000000..705d1af --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityDataFallingBlock.java @@ -0,0 +1,57 @@ +package ru.windcorp.progressia.test; + +import org.apache.logging.log4j.LogManager; + +import ru.windcorp.progressia.common.collision.AABB; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; + +/** + * Data for Test:FallingBlock + * + * @author opfromthestart + * + */ +public class TestEntityDataFallingBlock extends EntityData { + + private BlockData block; + private boolean isDone = false; + private boolean hasDeleted = false; + + public TestEntityDataFallingBlock() { + this("Test:FallingBlock", new BlockData("Test:LogTop")); + } + + public TestEntityDataFallingBlock(BlockData data) { + this("Test:FallingBlock", data); + } + + protected TestEntityDataFallingBlock(String id, BlockData blockInput) { + super(id); + setCollisionModel(new AABB(0, 0, 0, 1, 1, 1)); + block = blockInput; + LogManager.getLogger().info(blockInput.getId()); + } + + public void setDestroyed() { + hasDeleted = true; + } + + public boolean hasDestroyed() { + return hasDeleted; + } + + public BlockData getBlock() { + return block; + } + + public void setInvisible() { + // block = new BlockData("Test:Log"); + isDone = true; + setCollisionModel(new AABB(0, 0, 0, .5f, 0.5f, 0.5f)); + } + + public boolean isDone() { + return isDone; + } +} diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityDataStatie.java b/src/main/java/ru/windcorp/progressia/test/TestEntityDataStatie.java index 94f5043..6bbee70 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityDataStatie.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityDataStatie.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; import ru.windcorp.progressia.common.collision.AABB; diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityLogicFallingBlock.java b/src/main/java/ru/windcorp/progressia/test/TestEntityLogicFallingBlock.java new file mode 100644 index 0000000..03c725d --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityLogicFallingBlock.java @@ -0,0 +1,180 @@ +package ru.windcorp.progressia.test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.client.ClientState; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; +import ru.windcorp.progressia.server.world.entity.EntityLogic; +import ru.windcorp.progressia.test.Rocks.Rock; +import ru.windcorp.progressia.test.Rocks.RockVariant; + +/** + * Logic for Test:FallingBlock + * + * @author opfromthestart + * + */ +public class TestEntityLogicFallingBlock extends EntityLogic { + + public static Set FallingBlocks = new HashSet(); + + public void addFallables() { + FallingBlocks.add("Test:Sand"); + for (Rock rock : TestContent.ROCKS.getRocks()) + { + FallingBlocks.add(rock.getBlock(RockVariant.GRAVEL).getId()); + FallingBlocks.add(rock.getBlock(RockVariant.SAND).getId()); + } + } + + public TestEntityLogicFallingBlock(String id) { + super(id); + addFallables(); + } + + /*private Vec3i trueMod(Vec3i input, Vec3i modulus) // Move this to a class in + // Vec or something + { + return input.mod_(modulus).add_(modulus).mod_(modulus); + } + + private Vec3i trueDiv(Vec3i input, Vec3i divisor) // Move this to a class in + // Vec or something + { + Vec3i temp = input.div_(divisor); + temp.add(new Vec3i(input.x < 0 ? -1 : 0, input.y < 0 ? -1 : 0, input.z < 0 ? -1 : 0)); + return temp; + }*/ + + public Vec3i getBestCardinal(Vec3 dir) + { + Vec3 a = dir.abs_(); + if (a.x>a.y && a.x>a.z) + { + return new Vec3i(dir.x>0 ? 1 : -1,0,0); + } + else if (a.y>a.z) + { + return new Vec3i(0,dir.y>0 ? 1 : -1,0); + } + return new Vec3i(0,0,dir.z>0 ? 1 : -1); + } + + public List getGoodCardinals(Vec3 dir) + { + return getGoodCardinals(dir,.05f); + } + + public List getGoodCardinals(Vec3 dir, float d) { + List list = new ArrayList<>(); + Vec3 a = dir.abs_(); + if (a.x>d) + { + list.add(new Vec3i(dir.x>0 ? 1 : -1,0,0)); + } + if (a.y>d) + { + list.add(new Vec3i(0,dir.y>0 ? 1 : -1,0)); + } + if (a.z>d) + { + list.add(new Vec3i(0,0,dir.z>0 ? 1 : -1)); + } + return list; + } + + @Override + public void tick(EntityData entity, ServerWorldContext context) { // context.getWorldData() + // ClientState.getInstance().getWorld().getData() + + if (entity == null) { + return; + } + + + // LogManager.getLogger().info("NotNull "+entity.toString()+" + // "+String.valueOf(entity!=null) + " " + + // context.toString()); + super.tick(entity, context); + + + // friction + Vec3 vel = entity.getVelocity(); + float friction = 0f; + vel = new Vec3(vel.x * friction, vel.y * friction, vel.z); + entity.setVelocity(vel); + + //TestEntityDataFallingBlock fallBlock = (TestEntityDataFallingBlock) context.//context.getEntity(entity.getEntityId()); + + TestEntityDataFallingBlock fallBlock = (TestEntityDataFallingBlock) ClientState.getInstance().getWorld() + .getData().getEntity(entity.getEntityId()); + TestEntityDataFallingBlock fallBlock2 = (TestEntityDataFallingBlock) entity;// ClientState.getInstance().getWorld().getData().getEntity(entity.getEntityId()); + // fallBlock = (TestEntityDataFallingBlock) entity; + + // LogManager.getLogger().info("NotNull FB + // "+String.valueOf(fallBlock!=null)); + if (fallBlock == null) { + return; + } + + + + if (fallBlock.isDone() || context.getBlock(fallBlock.getBlockInWorld(null)) == null) { + return; + } + + //LogManager.getLogger().info("wut"); + + if (!fallBlock.hasDestroyed()) { + LogManager.getLogger().info(fallBlock.getPosition().x); + context.setBlock(fallBlock.getBlockInWorld(null), + BlockDataRegistry.getInstance().get("Test:Air")); + fallBlock.setDestroyed(); + } + + Vec3i occupiedBlock = fallBlock.getBlockInWorld(null); + Vec3i underBlock = occupiedBlock.sub_(getBestCardinal(fallBlock.getUpVector())); + List underBlocks = getGoodCardinals(fallBlock.getUpVector()); + + boolean notSupported = false; + for (Vec3i v3 : underBlocks) + { + Vec3i inWorld = occupiedBlock.sub_(v3); + if (context.getBlock(inWorld).getId()=="Test:Air") { + notSupported=true; + break; + } + } + + //LogManager.getLogger().info("InChunk + //"+String.valueOf(chunkCoords.x)+" "+String.valueOf(chunkCoords.y)+" + //"+String.valueOf(chunkCoords.z)+" "+String.valueOf(inChunkCoords.x)+" + ////"+String.valueOf(inChunkCoords.y)+" + //"+String.valueOf(inChunkCoords.z)); + /*LogManager.getLogger().info("FallingBlock is at {},{},{}", + String.valueOf(occupiedBlock.x), + String.valueOf(occupiedBlock.y), + String.valueOf(occupiedBlock.z));*/ + //LogManager.getLogger().info("Block is of type " + + //context.getWorldData().getChunk(chunkCoords).getBlock(inChunkCoords).getId()); + + if (context.getBlock(underBlock) != null + // && context.getBlock(underBlock).getId() != "Test:Air") { + && !notSupported) { + LogManager.getLogger().info("Deleting FallingBlock at " + String.valueOf(occupiedBlock.x) + " " + String.valueOf(occupiedBlock.y) + " " + String.valueOf(occupiedBlock.z)); + context.setBlock(occupiedBlock, fallBlock2.getBlock()); + fallBlock.setInvisible(); + //server.invokeLater(() -> server.getWorld().getData().removeEntity(entity.getEntityId())); + context.removeEntity(fallBlock); + } + } +} diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityLogicStatie.java b/src/main/java/ru/windcorp/progressia/test/TestEntityLogicStatie.java index 5fa66fb..4862d59 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityLogicStatie.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityLogicStatie.java @@ -15,11 +15,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.server.world.TickContext; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; import ru.windcorp.progressia.server.world.entity.EntityLogic; public class TestEntityLogicStatie extends EntityLogic { @@ -29,13 +29,13 @@ public class TestEntityLogicStatie extends EntityLogic { } @Override - public void tick(EntityData entity, TickContext context) { + public void tick(EntityData entity, ServerWorldContext context) { super.tick(entity, context); TestEntityDataStatie statie = (TestEntityDataStatie) entity; int size = (int) (18 + 6 * Math.sin(entity.getAge())); - context.getServer().getWorldAccessor().changeEntity(statie, e -> e.setSizeNow(size)); + context.changeEntity(statie, e -> e.setSizeNow(size)); } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderFallingBlock.java b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderFallingBlock.java new file mode 100644 index 0000000..ab121e3 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderFallingBlock.java @@ -0,0 +1,56 @@ +package ru.windcorp.progressia.test; + +import ru.windcorp.progressia.client.ClientState; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.client.graphics.model.Shapes; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; +import ru.windcorp.progressia.client.world.block.BlockRenderRegistry; +import ru.windcorp.progressia.client.world.entity.EntityRender; +import ru.windcorp.progressia.client.world.entity.EntityRenderable; +import ru.windcorp.progressia.common.world.entity.EntityData; + +/** + * Renderer for Test:FallingBlock + * + * @author opfromthestart + * + */ +public class TestEntityRenderFallingBlock extends EntityRender { + private Renderable cube; + + public TestEntityRenderFallingBlock(String id) { + super(id); + String dflt = TestEntityLogicFallingBlock.FallingBlocks.toArray()[0].toString().substring(5); + cube = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), BlockRenderRegistry.getBlockTexture(dflt ) )// TODO idk actual ggood this + .create(); + } + + public void setTexture(Texture texture) { // There has to be a better way. + cube = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), texture).create(); + } + + @Override + public EntityRenderable createRenderable(EntityData entity) { + return new EntityRenderable(entity) { + @Override + public void doRender(ShapeRenderHelper renderer) { + // LogManager.getLogger().info("Rendering FallingBlock"); + if (((TestEntityDataFallingBlock) entity).isDone()) { + return; + // setTexture(new + // SimpleTexture(Atlases.getSprite(ResourceManager.getTextureResource("blocks/LogSide"), + // new AtlasGroup("Blocks", 1 << 12)))); + } + TestEntityDataFallingBlock fallEntity = (TestEntityDataFallingBlock) ClientState.getInstance().getWorld().getData().getEntity(entity.getEntityId()); + setTexture(BlockRenderRegistry.getBlockTexture(fallEntity.getBlock().getId().substring(5))); + // setTexture(new + // SimpleTexture(Atlases.getSprite(ResourceManager.getTextureResource("blocks/Sand"), + // new AtlasGroup("Blocks", 1 << 12)))); + cube.render(renderer); + } + }; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderHuman.java b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderHuman.java index 388d89c..31b73ca 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderHuman.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderHuman.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; import static java.lang.Math.toRadians; @@ -56,11 +56,7 @@ public class TestEntityRenderHuman extends EntityRender { this.skin = fetchSkin(); - ComplexTexture texture = new ComplexTexture( - this.skin, - 16, - 16 - ); + ComplexTexture texture = new ComplexTexture(this.skin, 16, 16); this.body = createBody(texture); this.head = createHead(texture); @@ -80,109 +76,37 @@ public class TestEntityRenderHuman extends EntityRender { } private Renderable createBody(ComplexTexture texture) { - return createLayeredCuboid( - texture, - 4, - 8, - 4, - 4, - 2, - 3, - 1, - -0.5f, - -1, - 3, - 1, - 2, - 3 - ); + return createLayeredCuboid(texture, 4, 8, 4, 4, 2, 3, 1, -0.5f, -1, 3, 1, 2, 3); } private Renderable createHead(ComplexTexture texture) { - return createLayeredCuboid( - texture, - 0, - 12, - 8, - 12, - 2, - 2, - 2, - -1, - -1, - 0, - 2, - 2, - 2 - ); + return createLayeredCuboid(texture, 0, 12, 8, 12, 2, 2, 2, -1, -1, 0, 2, 2, 2); } - private Renderable createLimb( - ComplexTexture texture, - int tx, - int ty, - int tx2, - int ty2, - boolean isArm, - boolean isLeft - ) { - Renderable model = createLayeredCuboid( - texture, - tx, - ty, - tx2, - ty2, - 1, - 3, - 1, - -0.5f, - -0.5f, - isArm ? -2.5f : -3f, - 1, - 1, - 3 - ); + private Renderable createLimb(ComplexTexture texture, int tx, int ty, int tx2, int ty2, boolean isArm, + boolean isLeft) { + Renderable model = createLayeredCuboid(texture, tx, ty, tx2, ty2, 1, 3, 1, -0.5f, -0.5f, isArm ? -2.5f : -3f, 1, + 1, 3); if (isArm) { - return LambdaModel.animate( - model, - mat -> { - double phase = GraphicsInterface.getTime() + (isLeft ? 0 : Math.PI / 3); - mat.rotateX((isLeft ? +1 : -1) * 1 / 40f * (sin(phase) + 1)); - mat.rotateY(1 / 20f * sin(Math.PI / 3 * phase)); - } - ); + return LambdaModel.animate(model, mat -> { + double phase = GraphicsInterface.getTime() + (isLeft ? 0 : Math.PI / 3); + mat.rotateX((isLeft ? +1 : -1) * 1 / 40f * (sin(phase) + 1)); + mat.rotateY(1 / 20f * sin(Math.PI / 3 * phase)); + }); } else { return model; } } - private Renderable createLayeredCuboid( - ComplexTexture texture, - int tx, - int ty, - int tx2, - int ty2, - int tw, - int th, - int td, - float ox, - float oy, - float oz, - float sx, - float sy, - float sz - ) { + private Renderable createLayeredCuboid(ComplexTexture texture, int tx, int ty, int tx2, int ty2, int tw, int th, + int td, float ox, float oy, float oz, float sx, float sy, float sz) { WorldRenderProgram program = WorldRenderProgram.getDefault(); StaticModel.Builder b = StaticModel.builder(); // First layer - b.addPart( - new PppBuilder( - program, - texture.getCuboidTextures(tx, ty, tw, th, td) - ).setOrigin(ox, oy, oz).setSize(sx, sy, sz).create() - ); + b.addPart(new PppBuilder(program, texture.getCuboidTextures(tx, ty, tw, th, td)).setOrigin(ox, oy, oz) + .setSize(sx, sy, sz).create()); ox -= SECOND_LAYER_OFFSET; oy -= SECOND_LAYER_OFFSET; @@ -193,55 +117,25 @@ public class TestEntityRenderHuman extends EntityRender { sz += SECOND_LAYER_OFFSET * 2; // Second layer - b.addPart( - new PppBuilder( - program, - texture.getCuboidTextures(tx2, ty2, tw, th, td) - ).setOrigin(ox, oy, oz).setSize(sx, sy, sz).create() - ); + b.addPart(new PppBuilder(program, texture.getCuboidTextures(tx2, ty2, tw, th, td)).setOrigin(ox, oy, oz) + .setSize(sx, sy, sz).create()); return b.build(); } @Override public EntityRenderable createRenderable(EntityData entity) { - return new HumanoidModel( - entity, + return new HumanoidModel(entity, - new HumanoidModel.Body(body), - new HumanoidModel.Head( - head, - new Vec3(0, 0, 6), - 70, - 25, - new Vec3(1.2f, 0, 1.5f) - ), - new HumanoidModel.Arm( - leftArm, - new Vec3(0, +1.5f, 3 + 3 - 0.5f), - 0.0f - ), - new HumanoidModel.Arm( - rightArm, - new Vec3(0, -1.5f, 3 + 3 - 0.5f), - FloatMathUtil.PI_F - ), - new HumanoidModel.Leg( - leftLeg, - new Vec3(0, +0.5f, 3), - FloatMathUtil.PI_F - ), - new HumanoidModel.Leg( - rightLeg, - new Vec3(0, -0.5f, 3), - 0.0f - ), + new HumanoidModel.Body(body), + new HumanoidModel.Head(head, new Vec3(0, 0, 6), 70, 25, new Vec3(1.2f, 0, 1.5f)), + new HumanoidModel.Arm(leftArm, new Vec3(0, +1.5f, 3 + 3 - 0.5f), 0.0f), + new HumanoidModel.Arm(rightArm, new Vec3(0, -1.5f, 3 + 3 - 0.5f), FloatMathUtil.PI_F), + new HumanoidModel.Leg(leftLeg, new Vec3(0, +0.5f, 3), FloatMathUtil.PI_F), + new HumanoidModel.Leg(rightLeg, new Vec3(0, -0.5f, 3), 0.0f), - 1.8f / (3 + 3 + 2) - ) - .setWalkingArmSwing((float) toRadians(30)) - .setWalkingLegSwing((float) toRadians(50)) - .setWalkingFrequency(0.15f / 60.0f); + 1.8f / (3 + 3 + 2)).setWalkingArmSwing((float) toRadians(30)).setWalkingLegSwing((float) toRadians(50)) + .setWalkingFrequency(0.15f / 60.0f); } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java index aefa1c6..56b71ea 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java @@ -25,8 +25,8 @@ import glm.vec._3.Vec3; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.ShapePart; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; import ru.windcorp.progressia.client.graphics.model.LambdaModel; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.model.Shape; @@ -39,8 +39,8 @@ import ru.windcorp.progressia.client.world.entity.EntityRender; import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry; import ru.windcorp.progressia.client.world.entity.EntityRenderable; import ru.windcorp.progressia.client.world.entity.QuadripedModel; -import ru.windcorp.progressia.common.world.block.BlockFace; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TestEntityRenderJavapony extends EntityRender { @@ -78,14 +78,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addStaticPart( new PppBuilder( WorldRenderProgram.getDefault(), - BlockFace.mapToFaces( - tailStartTexture, - tailStartTexture, - tailStartTexture, - tailStartTexture, - tailStartTexture, - tailStartTexture - ) + tailStartTexture ) .setOrigin(-60, -4, 14) .setDepth(32, 0, -16).setWidth(8).setHeight(8) @@ -97,14 +90,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addStaticPart( new PppBuilder( WorldRenderProgram.getDefault(), - BlockFace.mapToFaces( - neckTexture, - neckTexture, - neckTexture, - neckTexture, - neckTexture, - neckTexture - ) + neckTexture ) .setOrigin(0, -8, 8) .setWidth(16).setDepth(16).setHeight(2, 0, 16) @@ -124,11 +110,11 @@ public class TestEntityRenderJavapony extends EntityRender { private static Renderable createMainBody(ComplexTexture texture) { WorldRenderProgram program = WorldRenderProgram.getDefault(); - List faces = new ArrayList<>(); + List faces = new ArrayList<>(); // F BODY faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(80, 16, 32, 32), Colors.WHITE, @@ -141,7 +127,7 @@ public class TestEntityRenderJavapony extends EntityRender { // NECK BASE faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(80, 48, 32, 16), Colors.WHITE, @@ -154,7 +140,7 @@ public class TestEntityRenderJavapony extends EntityRender { // T BODY (BACK) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(128, 0, 32, 48), Colors.WHITE, @@ -167,7 +153,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BOTTOM B (upper) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(144, 48, 32, 16), Colors.WHITE, @@ -180,7 +166,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BOTTOM B (lower) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(144, 48, 32, 16), Colors.WHITE, @@ -193,7 +179,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BOTTOM B (stomach) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(144, 48, 32, 16), Colors.WHITE, @@ -206,7 +192,7 @@ public class TestEntityRenderJavapony extends EntityRender { // STOMACH faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(224, 96, 32, 32), Colors.WHITE, @@ -219,7 +205,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BOTTOM F faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(112, 48, 32, 16), Colors.WHITE, @@ -232,7 +218,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BODY L faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(112, 16, 16, 32), Colors.WHITE, @@ -245,7 +231,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BODY SIDES (left) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(96, 96, 32, 32), Colors.WHITE, @@ -258,7 +244,7 @@ public class TestEntityRenderJavapony extends EntityRender { // QT MARK (left) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(16, 96, 16, 32), Colors.WHITE, @@ -271,7 +257,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BODY R faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(64, 16, 16, 32), Colors.WHITE, @@ -284,7 +270,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BODY SIDES (right) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(96, 96, 32, 32), Colors.WHITE, @@ -297,7 +283,7 @@ public class TestEntityRenderJavapony extends EntityRender { // QT MARK (right) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(16, 96, 16, 32), Colors.WHITE, @@ -311,7 +297,7 @@ public class TestEntityRenderJavapony extends EntityRender { return new Shape( Usage.STATIC, program, - faces.toArray(new Face[faces.size()]) + faces.toArray(new ShapePart[faces.size()]) ); } @@ -360,7 +346,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addPart( new PppBuilder( program, - BlockFace.mapToFaces( + AbsFace.mapToFaces( texture.get(32, 64, 0, 0), texture.get(32, 64, 0, 0), texture.get(32 + 8, 64, 16, 8), @@ -375,7 +361,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addPart( new PppBuilder( program, - BlockFace.mapToFaces( + AbsFace.mapToFaces( texture.get(32, 64, 0, 0), texture.get(32, 64, 0, 0), texture.get(32 + 12, 64 + 8, 8, 4), @@ -416,7 +402,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addPart( new PppBuilder( program, - BlockFace.mapToFaces( + AbsFace.mapToFaces( texture.get(128, 96, 16, 16), texture.get(128, 96, 16, 16), texture.get(128, 96, 16, 32), diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderStatie.java b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderStatie.java index 47990fd..fa595e7 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderStatie.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderStatie.java @@ -44,7 +44,7 @@ public class TestEntityRenderStatie extends EntityRender { public EntityRenderable createRenderable(EntityData entity) { return new EntityRenderable(entity) { @Override - public void render(ShapeRenderHelper renderer) { + public void doRender(ShapeRenderHelper renderer) { renderer.pushTransform().scale( ((TestEntityDataStatie) entity).getSize() / 24.0f ); diff --git a/src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java b/src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java index 1674d5b..ac221d8 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java +++ b/src/main/java/ru/windcorp/progressia/test/TestMusicPlayer.java @@ -38,41 +38,41 @@ import ru.windcorp.progressia.common.resource.ResourceManager; import ru.windcorp.progressia.common.util.crash.CrashReports; public class TestMusicPlayer implements Runnable { - + private static final int MIN_SILENCE = 15 * 1000; // 15 seconds private static final int MAX_SILENCE = 60 * 1000; // one minute - + private static TestMusicPlayer instance = null; - + private final List compositions = new ArrayList<>(); - + private final Random random = new Random(); private long nextStart; private Sound lastStarted = null; - + public TestMusicPlayer() { this.nextStart = System.currentTimeMillis(); - + instance = this; } - + public static void start() { Thread thread = new Thread(new TestMusicPlayer(), "Music Thread"); thread.setDaemon(true); thread.start(); } - + @Override public void run() { loadCompositions(); - + if (compositions.isEmpty()) { LogManager.getLogger().warn("No music found"); return; } - + while (true) { - + try { synchronized (this) { while (true) { @@ -88,39 +88,39 @@ public class TestMusicPlayer implements Runnable { LogManager.getLogger().warn("Received interrupt in music thread, terminating thread..."); return; } - + startNextComposition(); - + } } private void loadCompositions() { try { - + Path directory = Paths.get("music"); - + if (!Files.isDirectory(directory)) { Files.createDirectories(directory); } - + Iterator it = Files.walk(directory).filter(Files::isRegularFile).iterator(); int i = 0; - + while (it.hasNext()) { String file = it.next().toString(); if (!file.endsWith(".ogg") && !file.endsWith(".oga")) { LogManager.getLogger().warn("Skipping " + file + ": not .ogg nor .oga"); } - + String id = "Progressia:Music" + (i++); - + AudioManager.loadSound(ResourceManager.getFileResource(file.toString()), id, AudioFormat.STEREO); SoundType composition = AudioRegistry.getInstance().get(id); compositions.add(composition); - + LogManager.getLogger().info("Loaded " + file); } - + } catch (IOException e) { throw CrashReports.report(e, "Could not load music"); } @@ -129,20 +129,21 @@ public class TestMusicPlayer implements Runnable { private synchronized void startNextComposition() { int index = random.nextInt(compositions.size()); SoundType composition = compositions.get(index); - + long now = System.currentTimeMillis(); long durationInMs = (long) (composition.getDuration() * 1000); long silence = random.nextInt(MAX_SILENCE - MIN_SILENCE) + MIN_SILENCE; - + nextStart = now + durationInMs + silence; - + lastStarted = new Music(composition); lastStarted.play(false); } - + public static void startNextNow() { - if (instance == null) return; - + if (instance == null) + return; + synchronized (instance) { instance.nextStart = System.currentTimeMillis(); instance.notifyAll(); diff --git a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java index 80e2146..f535f3f 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java +++ b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java @@ -20,8 +20,11 @@ package ru.windcorp.progressia.test; import glm.Glm; import glm.mat._3.Mat3; -import glm.vec._2.Vec2; +import glm.mat._4.Mat4; import glm.vec._3.Vec3; + +import java.util.function.Function; + import org.lwjgl.glfw.GLFW; import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.graphics.GUI; @@ -36,7 +39,9 @@ import ru.windcorp.progressia.client.graphics.input.bus.Input; import ru.windcorp.progressia.client.graphics.world.LocalPlayer; import ru.windcorp.progressia.client.localization.Localizer; import ru.windcorp.progressia.common.Units; -import ru.windcorp.progressia.common.util.FloatMathUtil; +import ru.windcorp.progressia.common.util.Matrices; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.tile.TileData; @@ -56,6 +61,8 @@ public class TestPlayerControls { // Horizontal and vertical max control speed when flying private static final float FLYING_SPEED = Units.get("6 m/s"); + + private static final Function SPRINTING_FLYING_SPEED = (f) -> {return Math.pow(f,.75)+2*FLYING_SPEED;}; // (0; 1], 1 is instant change, 0 is no control authority private static final float FLYING_CONTROL_AUTHORITY = Units.get("2 1/s"); @@ -82,8 +89,6 @@ public class TestPlayerControls { private double lastSpacePress = Double.NEGATIVE_INFINITY; private double lastSprintPress = Double.NEGATIVE_INFINITY; - private boolean useMinecraftGravity = false; - private int selectedBlock = 0; private int selectedTile = 0; private boolean isBlockSelected = true; @@ -101,24 +106,25 @@ public class TestPlayerControls { final float speed, authority; if (isFlying) { - speed = FLYING_SPEED; + double timeSinceLastSpacePress = GraphicsInterface.getTime() - lastSprintPress; + speed = isSprinting ? SPRINTING_FLYING_SPEED.apply(timeSinceLastSpacePress).floatValue() : FLYING_SPEED; authority = FLYING_CONTROL_AUTHORITY; } else { speed = isSprinting ? SPRINTING_SPEED : WALKING_SPEED; authority = WALKING_CONTROL_AUTHORITY; } - Mat3 angMat = new Mat3().identity().rotateZ(player.getYaw()); - Vec3 desiredVelocity = new Vec3(movementForward, -movementRight, 0); - - if (movementForward != 0 && movementRight != 0) + Mat3 movementTransform = getMovementTransform(player, null); + Vec3 desiredVelocity = new Vec3(movementForward, movementRight, 0); + if (movementForward != 0 && movementRight != 0) { desiredVelocity.normalize(); - angMat.mul_(desiredVelocity); // bug in jglm, .mul() and mul_() are - // swapped + } desiredVelocity.z = movementUp; + movementTransform.mul_(desiredVelocity); // bug in jglm, .mul() and .mul_() are + // swapped desiredVelocity.mul(speed); - Vec3 change = new Vec3() + Vec3 newVelocity = new Vec3() .set(desiredVelocity) .sub(player.getVelocity()) .mul((float) Math.exp(-authority * GraphicsInterface.getFrameLength())) @@ -126,10 +132,12 @@ public class TestPlayerControls { .add(desiredVelocity); if (!isFlying) { - change.z = player.getVelocity().z; + Vec3 up = player.getUpVector(); + Vec3 wantedVertical = VectorUtil.projectOnVector(player.getVelocity(), up, null); + VectorUtil.projectOnSurface(newVelocity, up).add(wantedVertical); } - player.getVelocity().set(change); + player.getVelocity().set(newVelocity); // THIS IS TERRIBLE TEST EntityData serverEntity = ServerState.getInstance().getWorld().getData() @@ -140,6 +148,22 @@ public class TestPlayerControls { } + private Mat3 getMovementTransform(EntityData player, Mat3 mat) { + if (mat == null) { + mat = new Mat3(); + } + + Vec3 f = player.getForwardVector(null); + Vec3 u = player.getUpVector(); + Vec3 s = u.cross_(f); + + return mat.set( + +f.x, +f.y, +f.z, + -s.x, -s.y, -s.z, + +u.x, +u.y, +u.z + ); + } + public void handleInput(Input input) { InputEvent event = input.getEvent(); @@ -213,12 +237,6 @@ public class TestPlayerControls { handleCameraMode(); break; - case GLFW.GLFW_KEY_G: - if (!event.isPress()) - return false; - handleGravitySwitch(); - break; - case GLFW.GLFW_KEY_L: if (!event.isPress()) return false; @@ -244,10 +262,11 @@ public class TestPlayerControls { double timeSinceLastSpacePress = GraphicsInterface.getTime() - lastSpacePress; if (isPressed && timeSinceLastSpacePress < MODE_SWITCH_MAX_DELAY) { - isSprinting = false; + //isSprinting = false; isFlying = !isFlying; updateGUI(); movementUp = +1; + timeSinceLastSpacePress = MODE_SWITCH_MAX_DELAY; } else { if (isFlying) { movementUp += +1 * multiplier; @@ -262,10 +281,12 @@ public class TestPlayerControls { } private void handleSprint(KeyEvent event) { + + //LogManager.getLogger().info("hi"); double timeSinceLastSpacePress = GraphicsInterface.getTime() - lastSprintPress; - if (event.isPress() && timeSinceLastSpacePress < MODE_SPRINT_SWITCH_MAX_DELAY && !isFlying) { + if (event.isPress() && timeSinceLastSpacePress < MODE_SPRINT_SWITCH_MAX_DELAY) { isSprinting = !isSprinting; updateGUI(); } @@ -283,7 +304,13 @@ public class TestPlayerControls { return; } - getEntity().getVelocity().add(0, 0, JUMP_VELOCITY * (useMinecraftGravity ? 2 : 1)); + Vec3 up = getEntity().getUpVector(); + + getEntity().getVelocity().add( + up.x * JUMP_VELOCITY, + up.y * JUMP_VELOCITY, + up.z * JUMP_VELOCITY + ); } private void handleShift(int multiplier) { @@ -323,11 +350,6 @@ public class TestPlayerControls { } } - private void handleGravitySwitch() { - useMinecraftGravity = !useMinecraftGravity; - updateGUI(); - } - private void handleLanguageSwitch() { Localizer localizer = Localizer.getInstance(); if (localizer.getLanguage().equals("ru-RU")) { @@ -344,29 +366,36 @@ public class TestPlayerControls { return; } - final float yawScale = -0.002f; - final float pitchScale = yawScale; + final double yawScale = -0.002f; + final double pitchScale = -yawScale; + final double pitchExtremum = Math.PI/2 * 0.95f; + + double yawChange = event.getChangeX() * yawScale; + double pitchChange = event.getChangeY() * pitchScale; EntityData player = getEntity(); + + double startPitch = player.getPitch(); + double endPitch = startPitch + pitchChange; + endPitch = Glm.clamp(endPitch, -pitchExtremum, +pitchExtremum); + pitchChange = endPitch - startPitch; + + Mat4 mat = Matrices.grab4(); + Vec3 lookingAt = Vectors.grab3(); + Vec3 rightVector = Vectors.grab3(); - normalizeAngles( - player.getDirection().add( - (float) (event.getChangeX() * yawScale), - (float) (event.getChangeY() * pitchScale) - ) - ); - } - - private void normalizeAngles(Vec2 dir) { - // Normalize yaw - dir.x = FloatMathUtil.normalizeAngle(dir.x); - - // Clamp pitch - dir.y = Glm.clamp( - dir.y, - -FloatMathUtil.PI_F / 2, - +FloatMathUtil.PI_F / 2 - ); + rightVector.set(player.getLookingAt()).cross(player.getUpVector()).normalize(); + + mat.identity() + .rotate((float) yawChange, player.getUpVector()) + .rotate((float) pitchChange, rightVector); + + VectorUtil.applyMat4(player.getLookingAt(), mat, lookingAt); + player.setLookingAt(lookingAt); + + Vectors.release(rightVector); + Vectors.release(lookingAt); + Matrices.release(mat); } private void onWheelScroll(WheelScrollEvent event) { @@ -430,10 +459,6 @@ public class TestPlayerControls { return isSprinting; } - public boolean useMinecraftGravity() { - return useMinecraftGravity; - } - public BlockData getSelectedBlock() { return TestContent.PLACEABLE_BLOCKS.get(selectedBlock); } diff --git a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java index 06afc77..c2df863 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java @@ -15,16 +15,16 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.block.BlockTickContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; import ru.windcorp.progressia.server.world.tile.HangingTileLogic; import ru.windcorp.progressia.server.world.tile.TickableTile; -import ru.windcorp.progressia.server.world.tile.TileTickContext; public class TestTileLogicGrass extends HangingTileLogic implements TickableTile { @@ -33,44 +33,40 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile } @Override - public boolean canOccupyFace(TileTickContext context) { - return context.getFace() != BlockFace.BOTTOM && super.canOccupyFace(context); + public boolean canOccupyFace(ServerTileContextRO context) { + return context.getFace() != RelFace.DOWN && super.canOccupyFace(context); } @Override - public boolean canOccupyFace(BlockFace face) { - return face != BlockFace.BOTTOM; + public boolean canOccupyFace(RelFace face) { + return face != RelFace.DOWN; } @Override - public TickingPolicy getTickingPolicy(TileTickContext context) { + public TickingPolicy getTickingPolicy(ServerTileContextRO context) { return TickingPolicy.RANDOM; } @Override - public void tick(TileTickContext context) { + public void tick(ServerTileContext context) { if (!isLocationSuitable(context)) { - context.removeThisTile(); + context.removeTile(); } } @Override - public boolean canBeSquashed(TileTickContext context) { + public boolean canBeSquashed(ServerTileContextRO context) { return true; } - private boolean isLocationSuitable(TileTickContext context) { + private boolean isLocationSuitable(ServerTileContextRO context) { return canOccupyFace(context) && isBlockAboveTransparent(context); } - private boolean isBlockAboveTransparent(BlockTickContext context) { - return context.evalNeighbor(BlockFace.TOP, bctxt -> { - BlockLogic block = bctxt.getBlock(); - if (block == null) - return true; - - return block.isTransparent(bctxt); - }); + private boolean isBlockAboveTransparent(ServerTileContextRO context) { + context.pushRelative(RelFace.UP); + BlockLogic block = context.logic().getBlock(); + return context.popAndReturn(block == null || block.isTransparent(context)); } } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java b/src/main/java/ru/windcorp/progressia/test/TestTileRenderGrass.java similarity index 70% rename from src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java rename to src/main/java/ru/windcorp/progressia/test/TestTileRenderGrass.java index c73647b..14b56c7 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTileRenderGrass.java @@ -16,17 +16,18 @@ * along with this program. If not, see . */ -package ru.windcorp.progressia.client.world.tile; +package ru.windcorp.progressia.test; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.client.world.tile.TileRenderSurface; +import ru.windcorp.progressia.common.world.rels.RelFace; -public class TileRenderGrass extends TileRenderSurface { +public class TestTileRenderGrass extends TileRenderSurface { private final Texture topTexture; private final Texture sideTexture; - public TileRenderGrass( + public TestTileRenderGrass( String id, Texture top, Texture side @@ -37,13 +38,13 @@ public class TileRenderGrass extends TileRenderSurface { } @Override - public Texture getTexture(BlockFace face) { - return (face == BlockFace.TOP) ? topTexture : sideTexture; + public Texture getTexture(RelFace face) { + return (face == RelFace.UP) ? topTexture : sideTexture; } @Override - public boolean isOpaque(BlockFace face) { - return face == BlockFace.TOP; + public boolean isOpaque(RelFace face) { + return face == RelFace.UP; } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java b/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java index 97a0d99..ebfafde 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java +++ b/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java @@ -34,9 +34,9 @@ import org.apache.logging.log4j.Logger; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.state.IOContext; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.io.ChunkIO; import ru.windcorp.progressia.server.Server; @@ -47,7 +47,7 @@ public class TestWorldDiskIO { private static final boolean ENABLE = false; - public static void saveChunk(ChunkData chunk, Server server) { + public static void saveChunk(DefaultChunkData chunk, Server server) { if (!ENABLE) return; @@ -83,12 +83,12 @@ public class TestWorldDiskIO { } } - private static void writeGenerationHint(ChunkData chunk, DataOutputStream output, Server server) + private static void writeGenerationHint(DefaultChunkData chunk, DataOutputStream output, Server server) throws IOException { server.getWorld().getGenerator().writeGenerationHint(output, chunk.getGenerationHint()); } - public static ChunkData tryToLoad(Vec3i chunkPos, WorldData world, Server server) { + public static DefaultChunkData tryToLoad(Vec3i chunkPos, DefaultWorldData world, Server server) { if (!ENABLE) return null; @@ -113,7 +113,7 @@ public class TestWorldDiskIO { } try { - ChunkData result = load(path, chunkPos, world, server); + DefaultChunkData result = load(path, chunkPos, world, server); LOG.debug( "Loaded {} {} {}", @@ -135,7 +135,7 @@ public class TestWorldDiskIO { } } - private static ChunkData load(Path path, Vec3i chunkPos, WorldData world, Server server) + private static DefaultChunkData load(Path path, Vec3i chunkPos, DefaultWorldData world, Server server) throws IOException, DecodingException { try ( @@ -143,13 +143,13 @@ public class TestWorldDiskIO { new InflaterInputStream(new BufferedInputStream(Files.newInputStream(path))) ) ) { - ChunkData chunk = ChunkIO.load(world, chunkPos, input, IOContext.SAVE); + DefaultChunkData chunk = ChunkIO.load(world, chunkPos, input, IOContext.SAVE); readGenerationHint(chunk, input, server); return chunk; } } - private static void readGenerationHint(ChunkData chunk, DataInputStream input, Server server) + private static void readGenerationHint(DefaultChunkData chunk, DataInputStream input, Server server) throws IOException, DecodingException { chunk.setGenerationHint(server.getWorld().getGenerator().readGenerationHint(input)); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/Fields.java b/src/main/java/ru/windcorp/progressia/test/gen/Fields.java new file mode 100644 index 0000000..86741df --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/Fields.java @@ -0,0 +1,321 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import kdotjpg.opensimplex2.areagen.OpenSimplex2S; +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.world.generation.planet.Planet; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; + +public class Fields { + + @FunctionalInterface + public interface Field { + double compute(double x, double y); + } + + public static class FieldSet extends Namespaced implements SurfaceFloatField { + + private final Field[] fields = new Field[AbsFace.getFaces().size()]; + + public FieldSet(String id) { + super(id); + } + + public void put(AbsFace face, Field field) { + fields[face.getId()] = field; + } + + public Field get(AbsFace face) { + return fields[face.getId()]; + } + + @Override + public float get(AbsFace face, float x, float y) { + float offset = DefaultChunkData.CHUNK_RADIUS - 0.5f; + return (float) fields[face.getId()].compute(x - offset, y - offset); + } + + } + + private final Random primitiveRandomizer; + + private final OpenSimplex2S noise; + + private final Map registeredFields = Collections.synchronizedMap(new HashMap<>()); + + private final Logger logger = LogManager.getLogger(getClass()); + + public Fields(long seed) { + this.primitiveRandomizer = new Random(seed); + this.noise = new OpenSimplex2S(seed); + } + + public Field register(String id, AbsFace face, Field f) { + Objects.requireNonNull(f, "f"); + Objects.requireNonNull(face, "face"); + + synchronized (registeredFields) { + FieldSet fieldSet = registeredFields.computeIfAbsent(id, FieldSet::new); + + Field previous = fieldSet.get(face); + if (previous != null) { + throw new IllegalArgumentException( + "Duplicate field definition " + id + ":" + face + " for fields " + f + " and " + previous + ); + } + fieldSet.put(face, f); + + logger.debug("Registering {}:{} in {}", id, face, getClass().getSimpleName()); + } + + return f; + } + + public SurfaceFloatField register(String id, Function fieldGenerator) { + for (AbsFace face : AbsFace.getFaces()) { + register(id, face, fieldGenerator.apply(face)); + } + return get(id); + } + + public SurfaceFloatField register(String id, Supplier fieldGenerator) { + for (AbsFace face : AbsFace.getFaces()) { + register(id, face, fieldGenerator.get()); + } + return get(id); + } + + public SurfaceFloatField get(String id) { + return registeredFields.get(id); + } + + public Field get(String id, AbsFace face) { + return registeredFields.get(id).get(face); + } + + public static Field cutoff(Field f, double outerRadius, double thickness) { + return (x, y) -> { + + double cutoffCoefficient = 1; + cutoffCoefficient *= cutoffFunction(outerRadius - x, thickness); + cutoffCoefficient *= cutoffFunction(outerRadius + x, thickness); + cutoffCoefficient *= cutoffFunction(outerRadius - y, thickness); + cutoffCoefficient *= cutoffFunction(outerRadius + y, thickness); + + if (cutoffCoefficient == 0) { + return 0; + } + + return cutoffCoefficient * f.compute(x, y); + + }; + } + + public static Field cutoff(Field f, Planet planet, double thickness) { + return cutoff(f, planet.getRadius() - Coordinates.CHUNK_SIZE, thickness); + } + + private static double cutoffFunction(double distanceToCutoffPoint, double thickness) { + if (distanceToCutoffPoint < 0) { + return 0; + } else if (distanceToCutoffPoint < thickness) { + double t = distanceToCutoffPoint / thickness; + return (1 - Math.cos(Math.PI * t)) / 2; + } else { + return 1; + } + } + + public Field primitive() { + double xOffset = primitiveRandomizer.nextDouble() * 200 - 100; + double yOffset = primitiveRandomizer.nextDouble() * 200 - 100; + double rotation = primitiveRandomizer.nextDouble() * 2 * Math.PI; + + double sin = Math.sin(rotation); + double cos = Math.cos(rotation); + + return (x, y) -> noise.noise2(x * cos - y * sin + xOffset, x * sin + y * cos + yOffset); + } + + public static Field add(Field a, Field b) { + return (x, y) -> a.compute(x, y) + b.compute(x, y); + } + + public static Field multiply(Field a, Field b) { + return (x, y) -> a.compute(x, y) * b.compute(x, y); + } + + public static Field add(Field... functions) { + return (x, y) -> { + double sum = 0; + for (Field function : functions) { + sum += function.compute(x, y); + } + return sum; + }; + } + + public static Field multiply(Field... functions) { + return (x, y) -> { + double product = 1; + for (Field function : functions) { + product *= function.compute(x, y); + } + return product; + }; + } + + public static Field tweak(Field f, double scale, double amplitude, double bias) { + return (x, y) -> f.compute(x / scale, y / scale) * amplitude + bias; + } + + public static Field tweak(Field f, double scale, double amplitude) { + return tweak(f, scale, amplitude, 0); + } + + public static Field scale(Field f, double scale) { + return tweak(f, scale, 1, 0); + } + + public static Field amplify(Field f, double amplitude) { + return tweak(f, 1, amplitude, 0); + } + + public static Field bias(Field f, double bias) { + return tweak(f, 1, 1, bias); + } + + public static Field octaves(Field f, double scaleFactor, double amplitudeFactor, int octaves) { + return (x, y) -> { + double result = 0; + + double scale = 1; + double amplitude = 1; + + for (int i = 0; i < octaves; ++i) { + result += f.compute(x * scale, y * scale) * amplitude; + scale *= scaleFactor; + amplitude /= amplitudeFactor; + } + + return result; + }; + } + + public static Field octaves(Field f, double factor, int octaves) { + return octaves(f, factor, factor, octaves); + } + + public static Field squash(Field f, double slope) { + return (x, y) -> 1 / (1 + Math.exp(-slope * f.compute(x, y))); + } + + public static Field ridge(Field f) { + return (x, y) -> 1 - Math.abs(f.compute(x, y)); + } + + public static Field clamp(Field f, double min, double max) { + return (x, y) -> Math.min(Math.max(f.compute(x, y), min), max); + } + + public static Field withMin(Field f, double min) { + return (x, y) -> Math.max(f.compute(x, y), min); + } + + public static Field withMax(Field f, double max) { + return (x, y) -> Math.min(f.compute(x, y), max); + } + + public static Field select(Field f, double target, double width) { + return (x, y) -> { + double value = f.compute(x, y); + if (value < target - width) { + return 0; + } else if (value < target) { + return (width - (target - value)) / width; + } else if (value < target + width) { + return (width - (value - target)) / width; + } else { + return 0; + } + }; + } + + public static Field selectPositive(Field f, double target, double width) { + return (x, y) -> { + double value = f.compute(x, y); + if (value < target - width) { + return 0; + } else if (value < target + width) { + return (width - (target - value)) / (2*width); + } else { + return 1; + } + }; + } + + public static Field selectNegative(Field f, double target, double width) { + return (x, y) -> { + double value = target - f.compute(x, y); + if (value < target - width) { + return 0; + } else if (value < target + width) { + return (width - (target - value)) / (2*width); + } else { + return 1; + } + }; + } + + public static Field cliff(Field f, double target, double featureWidth, double slopeWidth) { + return (x, y) -> { + double value = f.compute(x, y); + + if (value < target - featureWidth) { + return 0; + } else if (value < target - slopeWidth) { + double t = (value - (target - featureWidth)) / (featureWidth - slopeWidth); + return -0.5 + Math.cos(t * Math.PI) / 2; + } else if (value < target + slopeWidth) { + double t = (value - (target - slopeWidth)) / (2 * slopeWidth); + return -Math.cos(t * Math.PI); + } else if (value < target + featureWidth) { + double t = (value - (target + slopeWidth)) / (featureWidth - slopeWidth); + return +0.5 + Math.cos(t * Math.PI) / 2; + } else { + return 0; + } + }; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/MultiblockVegetationFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/MultiblockVegetationFeature.java new file mode 100644 index 0000000..5cfcc43 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/MultiblockVegetationFeature.java @@ -0,0 +1,148 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen; + +import java.util.Set; +import java.util.function.Consumer; + +import com.google.common.collect.ImmutableSet; + +import glm.vec._3.i.Vec3i; +import kdotjpg.opensimplex2.areagen.OpenSimplex2S; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceTopLayerFeature; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; + +public abstract class MultiblockVegetationFeature extends SurfaceTopLayerFeature { + + private final SurfaceFloatField selector; + private final OpenSimplex2S wavinessGenerator = new OpenSimplex2S(0); + + private final double maximumDensity; + + private final Set soilWhitelist; + + public MultiblockVegetationFeature(String id, SurfaceFloatField selector, double minimumPeriod) { + super(id); + this.selector = selector; + this.maximumDensity = 1 / minimumPeriod; + + ImmutableSet.Builder soilWhitelistBuilder = ImmutableSet.builder(); + createSoilWhitelist(soilWhitelistBuilder::add); + this.soilWhitelist = soilWhitelistBuilder.build(); + } + + protected void createSoilWhitelist(Consumer output) { + output.accept("Test:Dirt"); + } + + @Override + protected void processTopBlock(SurfaceBlockContext context) { + Vec3i location = context.getLocation(); + + if (location.z < 0) { + return; + } + + if (!soilWhitelist.isEmpty() && !soilWhitelist.contains(context.getBlock().getId())) { + return; + } + + double selectorValue = selector.get(context); + double chance = selectorValue * maximumDensity; + if (context.getRandom().nextDouble() >= chance) { + return; + } + + grow(context, selectorValue); + } + + protected abstract void grow(SurfaceBlockContext context, double selectorValue); + + @Override + protected boolean isSolid(SurfaceBlockContext context) { + return context.logic().getBlock().isSolid(RelFace.UP); + } + + /* + * Utilities + */ + + protected void setLeaves(SurfaceWorldContext context, Vec3i location, BlockData leaves) { + if (context.getBlock(location).getId().equals("Test:Air")) { + context.setBlock(location, leaves); + } + } + + protected void iterateBlob( + Vec3i center, + double horDiameter, + double vertDiameter, + double wavinessAmplitude, + double wavinessScale, + Consumer action + ) { + VectorUtil.iterateCuboidAround( + center.x, + center.y, + center.z, + (int) Math.ceil(horDiameter) / 2 * 2 + 5, + (int) Math.ceil(horDiameter) / 2 * 2 + 5, + (int) Math.ceil(vertDiameter) / 2 * 2 + 5, + pos -> { + + double sx = (pos.x - center.x) / horDiameter; + double sy = (pos.y - center.y) / horDiameter; + double sz = (pos.z - center.z) / vertDiameter; + + double radius = 1; + + if (wavinessAmplitude > 0) { + radius += wavinessAmplitude * wavinessGenerator.noise3_Classic( + sx / wavinessScale, + sy / wavinessScale, + sz / wavinessScale + ); + } + + if (sx * sx + sy * sy + sz * sz <= radius * radius) { + action.accept(pos); + } + + } + ); + } + + protected void iterateSpheroid( + Vec3i center, + double horDiameter, + double vertDiameter, + Consumer action + ) { + iterateBlob(center, horDiameter, vertDiameter, 0, 0, action); + } + + protected void iterateSphere(Vec3i center, double diameter, Consumer action) { + iterateBlob(center, diameter, diameter, 0, 0, action); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/RockLayer.java b/src/main/java/ru/windcorp/progressia/test/gen/RockLayer.java new file mode 100644 index 0000000..5b41ef1 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/RockLayer.java @@ -0,0 +1,57 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen; + +import ru.windcorp.progressia.common.util.noise.discrete.DiscreteNoise; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; + +public class RockLayer implements TerrainLayer { + + private final DiscreteNoise strata; + private final SurfaceFloatField depthOffsets; + + private final double horizontalScale = 200; + private final double verticalScale = 10; + private final double depthInfluense = 0.1; + + public RockLayer(DiscreteNoise strata, SurfaceFloatField depthOffsets) { + this.strata = strata; + this.depthOffsets = depthOffsets; + } + + @Override + public BlockData get(SurfaceBlockContext context, float depth) { + + double z = context.getLocation().z; + z -= depth * depthInfluense; + z += depthOffsets.get(context); + z /= verticalScale; + + return strata + .get( + context.getLocation().x / horizontalScale, + context.getLocation().y / horizontalScale, + z + ) + .get(context, depth); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestBushFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/TestBushFeature.java new file mode 100644 index 0000000..ca2765c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestBushFeature.java @@ -0,0 +1,49 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; + +public class TestBushFeature extends MultiblockVegetationFeature { + + private final BlockData trunk = BlockDataRegistry.getInstance().get("Test:Log"); + private final BlockData leaves = BlockDataRegistry.getInstance().get("Test:TemporaryLeaves"); + + public TestBushFeature(String id, SurfaceFloatField selector) { + super(id, selector, 7 * 7); + } + + @Override + protected void grow(SurfaceBlockContext context, double selectorValue) { + double size = selectorValue * randomDouble(context, 0.8, 1.2); + + Vec3i center = context.getLocation().add_(0, 0, 1); + + context.setBlock(center, trunk); + context.setBlock(center.add_(0, 0, 1), leaves); + + iterateBlob(center, stretch(size, 1.3, 2.5), stretch(size, 0.6, 1.5), 0.7, 2, p -> { + setLeaves(context, p, leaves); + }); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java new file mode 100644 index 0000000..cc1ff8b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java @@ -0,0 +1,128 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen; + +import static ru.windcorp.progressia.test.gen.Fields.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import ru.windcorp.progressia.common.Units; +import ru.windcorp.progressia.common.util.ArrayFloatRangeMap; +import ru.windcorp.progressia.common.util.FloatRangeMap; +import ru.windcorp.progressia.common.util.noise.discrete.WorleyProceduralNoise; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.generation.WorldGenerator; +import ru.windcorp.progressia.server.world.generation.planet.Planet; +import ru.windcorp.progressia.server.world.generation.planet.PlanetGenerator; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeature; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; +import ru.windcorp.progressia.test.Rocks.RockVariant; +import ru.windcorp.progressia.test.TestContent; + +public class TestGenerationConfig { + + private static final long SEED = "No bugs please".hashCode(); + + private static final float PLANET_RADIUS = Units.get("0.5 km"); + private static final float SURFACE_GRAVITY = Units.get("9.8 m/s^2"); + private static final float CURVATURE = Units.get("100 m"); + private static final float INNER_RADIUS = Units.get("200 m"); + + private static final Fields FIELDS = new Fields(SEED); + + public static Function createGenerator() { + + Planet planet = new Planet( + ((int) PLANET_RADIUS) / Coordinates.CHUNK_SIZE, + SURFACE_GRAVITY, + CURVATURE, + INNER_RADIUS + ); + + TestHeightMap heightMap = new TestHeightMap(planet, planet.getRadius() / 4, FIELDS); + + FloatRangeMap layers = new ArrayFloatRangeMap<>(); + registerTerrainLayers(layers); + + List features = new ArrayList<>(); + registerFeatures(features); + + return server -> new PlanetGenerator("Test:PlanetGenerator", server, planet, heightMap, layers, features); + + } + + private static void registerTerrainLayers(FloatRangeMap layers) { + BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); + BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); + + SurfaceFloatField cliffs = FIELDS.get("Test:CliffSelector"); + + WorleyProceduralNoise.Builder builder = WorleyProceduralNoise.builder(); + TestContent.ROCKS.getRocks().forEach(rock -> { + builder.add((c, d) -> { + if (c.getRandom().nextInt(3) == 0) { + return rock.getBlock(RockVariant.CRACKED); + } else { + return rock.getBlock(RockVariant.MONOLITH); + } + }, 1); + }); + SurfaceFloatField rockDepthOffsets = FIELDS.register( + "Test:RockDepthOffsets", + () -> tweak(FIELDS.primitive(), 40, 5) + ); + RockLayer rockLayer = new RockLayer(builder.build(SEED), rockDepthOffsets); + + layers.put(Float.NEGATIVE_INFINITY, 0, (c, d) -> air); + layers.put(0, 4, (c, d) -> { + if (cliffs.get(c.getSurface().getUp(), c.getLocation().x, c.getLocation().y) > 0) { + return rockLayer.get(c, d); + } else { + return dirt; + } + }); + layers.put(4, Float.POSITIVE_INFINITY, rockLayer); + } + + private static void registerFeatures(List features) { + + SurfaceFloatField forestiness = FIELDS.register( + "Test:Forestiness", + () -> squash(scale(FIELDS.primitive(), 200), 5) + ); + + SurfaceFloatField floweriness = FIELDS.register( + "Test:Floweriness", + f -> multiply( + scale(octaves(FIELDS.primitive(), 2, 2), 40), + tweak(FIELDS.get("Test:Forestiness", f), 1, -1, 1.1) + ) + ); + + features.add(new TestBushFeature("Test:BushFeature", forestiness)); + features.add(new TestTreeFeature("Test:TreeFeature", forestiness)); + features.add(new TestGrassFeature("Test:GrassFeature", FIELDS.get("Test:CliffSelector"), floweriness)); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java new file mode 100644 index 0000000..d1d73e5 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java @@ -0,0 +1,122 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen; + +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.common.world.tile.TileDataRegistry; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceTopLayerFeature; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; + +public class TestGrassFeature extends SurfaceTopLayerFeature { + + private static final Set WHITELIST = ImmutableSet.of( + "Test:Dirt", + "Test:Stone", + "Test:GraniteMonolith", + "Test:GraniteCracked", + "Test:GraniteGravel" + ); + + private final SurfaceFloatField grassiness; + private final SurfaceFloatField floweriness; + private final double scatterDensity = 1.0 / (3*3); + + private final TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); + private final List flowers = ImmutableList.of( + TileDataRegistry.getInstance().get("Test:YellowFlowers") + ); + private final List scatter = ImmutableList.of( + TileDataRegistry.getInstance().get("Test:Stones"), + TileDataRegistry.getInstance().get("Test:Sand") + ); + + public TestGrassFeature(String id, SurfaceFloatField grassiness, SurfaceFloatField floweriness) { + super(id); + this.grassiness = grassiness; + this.floweriness = floweriness; + } + + @Override + protected void processTopBlock(SurfaceBlockContext context) { + if (context.getLocation().z < 0) { + return; + } + if (!WHITELIST.contains(context.getBlock().getId())) { + return; + } + + if (!context.pushRelative(RelFace.UP).logic().getBlock().isTransparent()) { + context.pop(); + return; + } + context.pop(); + + double grassiness = this.grassiness.get(context); + if (grassiness < 0.2) { + growGrass(context); + } + + placeScatter(context); + + if (grassiness < 0.2) { + growFlowers(context); + } + } + + private void placeScatter(SurfaceBlockContext context) { + if (context.getRandom().nextDouble() < scatterDensity) { + TileData tile = pickRandom(context, scatter); + context.addTile(RelFace.UP, tile); + } + } + + private void growGrass(SurfaceBlockContext context) { + for (RelFace face : RelFace.getFaces()) { + if (face == RelFace.DOWN) continue; + + if (context.pushRelative(face).logic().getBlock().isTransparent()) { + context.pop(); + context.addTile(face, grass); + } else { + context.pop(); + } + + } + } + + private void growFlowers(SurfaceBlockContext context) { + if (context.getRandom().nextDouble() < floweriness.get(context)) { + TileData tile = pickRandom(context, flowers); + context.addTile(RelFace.UP, tile); + } + } + + @Override + protected boolean isSolid(SurfaceBlockContext context) { + return context.logic().getBlock().isSolid(RelFace.UP); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java new file mode 100644 index 0000000..a2a8a8d --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java @@ -0,0 +1,57 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.DecodingException; +import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.rels.AbsFace; + +public class TestGravityModel extends GravityModel { + + public TestGravityModel(String id) { + super(id); + } + + @Override + protected void doGetGravity(Vec3 pos, Vec3 output) { + output.set(0, 0, -9.8f); + } + + @Override + protected AbsFace doGetDiscreteUp(Vec3i chunkPos) { + AbsFace rounded = AbsFace.roundToFace(chunkPos.x, chunkPos.y, chunkPos.z - 54); + return rounded == null ? AbsFace.POS_Z : rounded; + } + + @Override + protected void doReadSettings(DataInput input) throws IOException, DecodingException { + // Do nothing + } + + @Override + protected void doWriteSettings(DataOutput output) throws IOException { + // Do nothing + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java b/src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java new file mode 100644 index 0000000..c09aec1 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java @@ -0,0 +1,79 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen; + +import static ru.windcorp.progressia.test.gen.Fields.*; + +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.world.generation.planet.Planet; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; + +public class TestHeightMap implements SurfaceFloatField { + + private final SurfaceFloatField shape; + + public TestHeightMap( + Planet planet, + float cutoffThickness, + Fields fields + ) { + + for (AbsFace face : AbsFace.getFaces()) { + + Field landmassDistribution = scale(octaves(fields.primitive(), 2, 5), 400); + Field landmasses = tweak(squash(landmassDistribution, 4), 1, 20, -20); + + Field plainsSelector = squash(withMin(landmassDistribution, 0), 10); + Field plains = tweak(octaves(fields.primitive(), 2, 3), 100, 3); + + Field randomCliffSelector = scale(fields.primitive(), 200); + randomCliffSelector = add( + select(randomCliffSelector, +0.7, 0.3), + amplify(select(randomCliffSelector, -0.7, 0.3), -1) + ); + Field randomCliffs = octaves(scale(fields.primitive(), 300), 3, 5); + + Field shoreCliffSelector = withMin(scale(fields.primitive(), 200), 0); + Field shoreCliffs = add( + landmassDistribution, + tweak(octaves(fields.primitive(), 2, 3), 50, 0.2) + ); + + fields.register("Test:CliffSelector", face, multiply( + shoreCliffSelector, + bias(select(shoreCliffs, 0, 0.07), 0) + )); + + fields.register("Test:Height", face, cutoff(add( + landmasses, + multiply(plains, plainsSelector), + multiply(amplify(cliff(randomCliffs, 0, 0.5, 0.03), 10), randomCliffSelector), + multiply(tweak(cliff(shoreCliffs, 0, 0.5, 0.03), 1, 15, 15), shoreCliffSelector) + ), planet, cutoffThickness)); + + } + + this.shape = fields.get("Test:Height"); + } + + @Override + public float get(AbsFace face, float x, float y) { + return (float) shape.get(face, x, y); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java deleted file mode 100644 index c4f5ec7..0000000 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.test.gen; - -import kdotjpg.opensimplex2.areagen.OpenSimplex2S; -import ru.windcorp.progressia.server.world.WorldLogic; - -class TestTerrainGenerator { - - @FunctionalInterface - private interface Func2D { - double compute(double x, double y); - } - - private final OpenSimplex2S noise; - private final Func2D shape; - - public TestTerrainGenerator(TestWorldGenerator testWorldGenerator, WorldLogic world) { - this.noise = new OpenSimplex2S("We're getting somewhere".hashCode()); - - Func2D plainsHeight = tweak( - octaves( - tweak(primitive(), 0.01, 0.5), - 2, - 3 - ), - 1, - 0.2, - 0.2 - ); - - Func2D mountainsHeight = tweak( - octaves( - ridge(tweak(primitive(), 0.01, 1)), - 2, - 1.5, - 12 - ), - 1, - 3 - ); - - Func2D mountainousity = tweak( - octaves( - tweak(primitive(), 0.007, 1), - 2, - 3 - ), - 1, - 1, - -0.25 - ); - - shape = tweak( - add(multiply(squash(mountainousity, 10), mountainsHeight), plainsHeight), - 0.001, - 1000, - 0 - ); - } - - public void compute(int startX, int startY, double[][] heightMap, double[][] slopeMap) { - for (int x = 0; x < heightMap.length; ++x) { - for (int y = 0; y < heightMap.length; ++y) { - heightMap[x][y] = shape.compute(x + startX, y + startY); - slopeMap[x][y] = computeSlope(shape, x + startX, y + startY, heightMap[x][y]); - } - } - } - - private double computeSlope(Func2D f, double x0, double y0, double f0) { - double di = 0.5; - - double dfdx = (f.compute(x0 + di, y0) - f0) / di; - double dfdy = (f.compute(x0, y0 + di) - f0) / di; - - return Math.hypot(dfdx, dfdy); - } - - /* - * Utility functions - */ - - private Func2D primitive() { - return noise::noise2; - } - - private Func2D add(Func2D a, Func2D b) { - return (x, y) -> a.compute(x, y) + b.compute(x, y); - } - - private Func2D multiply(Func2D a, Func2D b) { - return (x, y) -> a.compute(x, y) * b.compute(x, y); - } - - private Func2D tweak(Func2D f, double scale, double amplitude, double bias) { - return (x, y) -> f.compute(x * scale, y * scale) * amplitude + bias; - } - - private Func2D tweak(Func2D f, double scale, double amplitude) { - return tweak(f, scale, amplitude, 0); - } - - private Func2D octaves(Func2D f, double scaleFactor, double amplitudeFactor, int octaves) { - return (x, y) -> { - double result = 0; - - double scale = 1; - double amplitude = 1; - - for (int i = 0; i < octaves; ++i) { - result += f.compute(x * scale, y * scale) * amplitude; - scale *= scaleFactor; - amplitude /= amplitudeFactor; - } - - return result; - }; - } - - private Func2D octaves(Func2D f, double factor, int octaves) { - return octaves(f, factor, factor, octaves); - } - - private Func2D squash(Func2D f, double slope) { - return (x, y) -> 1 / (1 + Math.exp(-slope * f.compute(x, y))); - } - - private Func2D ridge(Func2D f) { - return (x, y) -> { - double result = 1 - Math.abs(f.compute(x, y)); - return result * result; - }; - } - -} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestTreeFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/TestTreeFeature.java new file mode 100644 index 0000000..d08862e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestTreeFeature.java @@ -0,0 +1,69 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; + +public class TestTreeFeature extends MultiblockVegetationFeature { + + private final BlockData trunk = BlockDataRegistry.getInstance().get("Test:Log"); + private final BlockData leaves = BlockDataRegistry.getInstance().get("Test:TemporaryLeaves"); + + public TestTreeFeature(String id, SurfaceFloatField selector) { + super(id, selector, 10 * 10); + } + + @Override + protected void grow(SurfaceBlockContext context, double selectorValue) { + + Vec3i start = context.getLocation().add_(0, 0, 1); + Vec3i center = start.add_(0); + + double size = selectorValue * randomDouble(context, 0.8, 1.2); + + int height = (int) stretch(size, 3, 7); + for (; center.z < start.z + height; ++center.z) { + context.setBlock(center, trunk); + } + + double branchHorDistance = 0; + + do { + double branchSize = 0.5 + randomDouble(context, 1, 2) * size; + double branchHorAngle = randomDouble(context, 0, 2 * Math.PI); + int branchVertOffset = (int) randomDouble(context, -2, 0); + + Vec3i branchCenter = center.add_( + (int) (Math.sin(branchHorAngle) * branchHorDistance), + (int) (Math.cos(branchHorAngle) * branchHorDistance), + branchVertOffset + ); + + iterateBlob(branchCenter, 1 * branchSize, 2.3 * branchSize, 0.5, 3, p -> { + setLeaves(context, p, leaves); + }); + + branchHorDistance = randomDouble(context, 0.7, 1.5); + } while (context.getRandom().nextInt(8) > 1); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java deleted file mode 100644 index 1b35ffc..0000000 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Progressia - * Copyright (C) 2020-2021 Wind Corporation and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.windcorp.progressia.test.gen; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Random; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.VectorUtil; -import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.WorldDataListener; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataRegistry; -import ru.windcorp.progressia.server.world.WorldLogic; -import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; - -public class TestWorldGenerator extends AbstractWorldGenerator { - - private final TestTerrainGenerator terrainGen; - - public TestWorldGenerator(WorldLogic world) { - super("Test:WorldGenerator", Boolean.class); - this.terrainGen = new TestTerrainGenerator(this, world); - - world.getData().addListener(new WorldDataListener() { - @Override - public void onChunkLoaded(WorldData world, ChunkData chunk) { - findAndPopulate(chunk.getPosition(), world); - } - }); - } - - @Override - protected Boolean doReadGenerationHint(DataInputStream input) throws IOException, DecodingException { - return input.readBoolean(); - } - - @Override - protected void doWriteGenerationHint(DataOutputStream output, Boolean hint) throws IOException { - output.writeBoolean(hint); - } - - @Override - protected boolean checkIsChunkReady(Boolean hint) { - return hint; - } - - @Override - public ChunkData generate(Vec3i chunkPos, WorldData world) { - ChunkData chunk = generateUnpopulated(chunkPos, world); - world.addChunk(chunk); - return chunk; - } - - private ChunkData generateUnpopulated(Vec3i chunkPos, WorldData world) { - ChunkData chunk = new ChunkData(chunkPos, world); - chunk.setGenerationHint(false); - - final int bpc = ChunkData.BLOCKS_PER_CHUNK; - Random random = new Random(chunkPos.x + chunkPos.y + chunkPos.z); - - BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); - BlockData stone = BlockDataRegistry.getInstance().get("Test:Stone"); - BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); - - BlockData[] granites = new BlockData[] { - BlockDataRegistry.getInstance().get("Test:GraniteGravel"), - BlockDataRegistry.getInstance().get("Test:GraniteGravel"), - BlockDataRegistry.getInstance().get("Test:GraniteCracked"), - BlockDataRegistry.getInstance().get("Test:GraniteMonolith") - }; - - double[][] heightMap = new double[bpc][bpc]; - double[][] gradMap = new double[bpc][bpc]; - - int startX = Coordinates.getInWorld(chunk.getX(), 0); - int startY = Coordinates.getInWorld(chunk.getY(), 0); - int startZ = Coordinates.getInWorld(chunk.getZ(), 0); - - terrainGen.compute(startX, startY, heightMap, gradMap); - - VectorUtil.iterateCuboid(0, 0, 0, bpc, bpc, bpc, pos -> { - double layer = pos.z - heightMap[pos.x][pos.y] + startZ; - - if (layer < -4) { - chunk.setBlock(pos, stone, false); - } else if (layer < 0) { - if (gradMap[pos.x][pos.y] > 0.5) { - BlockData granite = granites[random.nextInt(4)]; - chunk.setBlock(pos, granite, false); - } else { - chunk.setBlock(pos, dirt, false); - } - } else { - chunk.setBlock(pos, air, false); - } - }); - - return chunk; - } - - private void findAndPopulate(Vec3i changePos, WorldData world) { - VectorUtil.iterateCuboidAround(changePos, 3, candidatePos -> { - if (canBePopulated(candidatePos, world)) { - populate(candidatePos, world); - } - }); - } - - private boolean canBePopulated(Vec3i candidatePos, WorldData world) { - Vec3i cursor = Vectors.grab3i(); - - ChunkData candidate = world.getChunk(candidatePos); - if (candidate == null || isChunkReady(candidate.getGenerationHint())) - return false; - - for (int dx = -1; dx <= 1; ++dx) { - cursor.x = candidatePos.x + dx; - for (int dy = -1; dy <= 1; ++dy) { - cursor.y = candidatePos.y + dy; - for (int dz = -1; dz <= 1; ++dz) { - - if ((dx | dy | dz) == 0) - continue; - - cursor.z = candidatePos.z + dz; - - ChunkData chunk = world.getChunk(cursor); - if (chunk == null) { - return false; - } - - } - } - } - - Vectors.release(cursor); - return true; - } - - private void populate(Vec3i chunkPos, WorldData world) { - Random random = new Random(chunkPos.x + chunkPos.y + chunkPos.z); - - ChunkData chunk = world.getChunk(chunkPos); - assert chunk != null : "Something went wrong when populating chunk at (" + chunkPos.x + "; " + chunkPos.y + "; " - + chunkPos.z + ")"; - - BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); - BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); - - Vec3i biw = new Vec3i(); - - int minX = chunk.getMinX(); - int maxX = chunk.getMaxX() + 1; - int minY = chunk.getMinY(); - int maxY = chunk.getMaxY() + 1; - int minZ = chunk.getMinZ(); - int maxZ = chunk.getMaxZ() + 1; - - final int bpc = ChunkData.BLOCKS_PER_CHUNK; - double[][] heightMap = new double[bpc][bpc]; - double[][] gradMap = new double[bpc][bpc]; - - terrainGen.compute(minX, minY, heightMap, gradMap); - - for (biw.x = minX; biw.x < maxX; ++biw.x) { - for (biw.y = minY; biw.y < maxY; ++biw.y) { - - for (biw.z = minZ; biw.z < maxZ + 1 && world.getBlock(biw) != air; ++biw.z) - ; - biw.z -= 1; - - if (biw.z == maxZ) - continue; - if (biw.z < minZ) - continue; - - int xic = Coordinates.convertInWorldToInChunk(biw.x); - int yic = Coordinates.convertInWorldToInChunk(biw.y); - - addTiles( - chunk, - biw, - world, - random, - world.getBlock(biw) == dirt, - heightMap[xic][yic], - gradMap[xic][yic] - ); - - } - } - - chunk.setGenerationHint(true); - } - - private void addTiles( - ChunkData chunk, - Vec3i biw, - WorldData world, - Random random, - boolean isDirt, - double height, - double grad - ) { - if (isDirt) - addGrass(chunk, biw, world, random); - addDecor(chunk, biw, world, random, isDirt); - addSnow(chunk, biw, world, random, isDirt, height, grad); - } - - private void addGrass(ChunkData chunk, Vec3i biw, WorldData world, Random random) { - BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); - TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); - - world.getTiles(biw, BlockFace.TOP).add(grass); - - for (BlockFace face : BlockFace.getFaces()) { - if (face.getVector().z != 0) - continue; - biw.add(face.getVector()); - - if (world.getBlock(biw) == air) { - biw.sub(face.getVector()); - world.getTiles(biw, face).add(grass); - } else { - biw.sub(face.getVector()); - } - } - } - - private void addDecor(ChunkData chunk, Vec3i biw, WorldData world, Random random, boolean isDirt) { - if (isDirt) { - if (random.nextInt(8) == 0) { - world.getTiles(biw, BlockFace.TOP).addFarthest( - TileDataRegistry.getInstance().get("Test:Sand") - ); - } - - if (random.nextInt(8) == 0) { - world.getTiles(biw, BlockFace.TOP).addFarthest( - TileDataRegistry.getInstance().get("Test:Stones") - ); - } - - if (random.nextInt(8) == 0) { - world.getTiles(biw, BlockFace.TOP).addFarthest( - TileDataRegistry.getInstance().get("Test:YellowFlowers") - ); - } - } else { - if (random.nextInt(2) == 0) { - world.getTiles(biw, BlockFace.TOP).addFarthest( - TileDataRegistry.getInstance().get("Test:Stones") - ); - } - } - } - - private void addSnow( - ChunkData chunk, - Vec3i biw, - WorldData world, - Random random, - boolean isDirt, - double height, - double grad - ) { - if (height < 1500) - return; - - BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); - - double quarterChance = computeSnowQuarterChance(height, grad); - double halfChance = computeSnowHalfChance(height, grad); - double opaqueChance = computeSnowOpaqueChance(height, grad); - - for (BlockFace face : BlockFace.getFaces()) { - if (face == BlockFace.BOTTOM) - continue; - - if (face.getVector().z == 0) { - biw.add(face.getVector()); - BlockData neighbour = world.getBlock(biw); - biw.sub(face.getVector()); - - if (neighbour != air) - continue; - } - - TileData tile; - - double maxValue = height > 3000 ? 3 : (1 + 2 * ((height - 1500) / 1500)); - double value = random.nextDouble() * maxValue; - if (value < quarterChance) { - tile = TileDataRegistry.getInstance().get("Test:SnowQuarter"); - } else if ((value -= quarterChance) < halfChance) { - tile = TileDataRegistry.getInstance().get("Test:SnowHalf"); - } else if ((value -= halfChance) < opaqueChance) { - tile = TileDataRegistry.getInstance().get("Test:SnowOpaque"); - } else { - tile = null; - } - - if (tile != null) { - world.getTiles(biw, face).addFarthest(tile); - } - } - } - - private double computeSnowQuarterChance(double height, double grad) { - double heightCoeff; - - if (height < 1500) - heightCoeff = 0; - else if (height < 2000) - heightCoeff = (height - 1500) / 500; - else - heightCoeff = 1; - - if (heightCoeff < 1e-4) - return 0; - - double gradCoeff = computeSnowGradCoeff(height, grad); - return heightCoeff * gradCoeff; - } - - private double computeSnowHalfChance(double height, double grad) { - double heightCoeff; - - if (height < 2000) - heightCoeff = 0; - else if (height < 2500) - heightCoeff = (height - 2000) / 500; - else - heightCoeff = 1; - - if (heightCoeff < 1e-4) - return 0; - - double gradCoeff = computeSnowGradCoeff(height, grad); - return heightCoeff * gradCoeff; - } - - private double computeSnowOpaqueChance(double height, double grad) { - double heightCoeff; - - if (height < 2500) - heightCoeff = 0; - else if (height < 3000) - heightCoeff = (height - 2500) / 500; - else - heightCoeff = 1; - - if (heightCoeff < 1e-4) - return 0; - - double gradCoeff = computeSnowGradCoeff(height, grad); - return heightCoeff * gradCoeff; - } - - private double computeSnowGradCoeff(double height, double grad) { - final double a = -0.00466666666666667; - final double b = 12.66666666666667; - double characteristicGrad = 1 / (a * height + b); - return Math.exp(-grad / characteristicGrad); - } - -} diff --git a/src/main/resources/assets/languages/en-US.lang b/src/main/resources/assets/languages/en-US.lang index 4935e77..e2ff70b 100644 --- a/src/main/resources/assets/languages/en-US.lang +++ b/src/main/resources/assets/languages/en-US.lang @@ -7,12 +7,11 @@ LayerAbout.DebugHint = Debug GUI: F3 LayerTestGUI.IsFlyingDisplay = Flying: %5s (Space bar x2) LayerTestGUI.IsSprintingDisplay = Sprinting: %5s (W x2) LayerTestGUI.CameraModeDisplay = Camera mode: %5d (F5) -LayerTestGUI.GravityModeDisplay = Gravity: %9s (G) LayerTestGUI.LanguageDisplay = Language: %5s (L) LayerTestGUI.FPSDisplay = FPS: LayerTestGUI.TPSDisplay = TPS: LayerTestGUI.TPSDisplay.NA = TPS: n/a -LayerTestGUI.ChunkUpdatesDisplay = Pending updates: +LayerTestGUI.ChunkStatsDisplay = Chunks vis/pnd/load: LayerTestGUI.PosDisplay = Pos: LayerTestGUI.PosDisplay.NA.Client = Pos: client n/a LayerTestGUI.PosDisplay.NA.Entity = Pos: entity n/a diff --git a/src/main/resources/assets/languages/ru-RU.lang b/src/main/resources/assets/languages/ru-RU.lang index cd10faa..97935d6 100644 --- a/src/main/resources/assets/languages/ru-RU.lang +++ b/src/main/resources/assets/languages/ru-RU.lang @@ -7,12 +7,11 @@ LayerAbout.DebugHint = Отладочный GUI: F3 LayerTestGUI.IsFlyingDisplay = Полёт: %5s (Пробел x2) LayerTestGUI.IsSprintingDisplay = Бег: %5s (W x2) LayerTestGUI.CameraModeDisplay = Камера: %5d (F5) -LayerTestGUI.GravityModeDisplay = Гравитация: %9s (G) LayerTestGUI.LanguageDisplay = Язык: %5s (L) LayerTestGUI.FPSDisplay = FPS: LayerTestGUI.TPSDisplay = TPS: LayerTestGUI.TPSDisplay.NA = TPS: н/д -LayerTestGUI.ChunkUpdatesDisplay = Обновления в очереди: +LayerTestGUI.ChunkStatsDisplay = Чанки вид/очр/загр: LayerTestGUI.PosDisplay = Поз: LayerTestGUI.PosDisplay.NA.Client = Поз: клиент н/д LayerTestGUI.PosDisplay.NA.Entity = Поз: сущность н/д diff --git a/src/main/resources/assets/textures/blocks/BlackGraniteCracked.png b/src/main/resources/assets/textures/blocks/BlackGraniteCracked.png new file mode 100644 index 0000000..5d3afa4 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/BlackGraniteCracked.png differ diff --git a/src/main/resources/assets/textures/blocks/BlackGraniteGravel.png b/src/main/resources/assets/textures/blocks/BlackGraniteGravel.png new file mode 100644 index 0000000..bd49f48 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/BlackGraniteGravel.png differ diff --git a/src/main/resources/assets/textures/blocks/BlackGraniteMonolith.png b/src/main/resources/assets/textures/blocks/BlackGraniteMonolith.png new file mode 100644 index 0000000..2aff002 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/BlackGraniteMonolith.png differ diff --git a/src/main/resources/assets/textures/blocks/BlackGraniteSand.png b/src/main/resources/assets/textures/blocks/BlackGraniteSand.png new file mode 100644 index 0000000..71b867e Binary files /dev/null and b/src/main/resources/assets/textures/blocks/BlackGraniteSand.png differ diff --git a/src/main/resources/assets/textures/blocks/DolomiteCracked.png b/src/main/resources/assets/textures/blocks/DolomiteCracked.png new file mode 100644 index 0000000..46feff6 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/DolomiteCracked.png differ diff --git a/src/main/resources/assets/textures/blocks/DolomiteGravel.png b/src/main/resources/assets/textures/blocks/DolomiteGravel.png new file mode 100644 index 0000000..7b28fa6 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/DolomiteGravel.png differ diff --git a/src/main/resources/assets/textures/blocks/DolomiteMonolith.png b/src/main/resources/assets/textures/blocks/DolomiteMonolith.png new file mode 100644 index 0000000..0cdc259 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/DolomiteMonolith.png differ diff --git a/src/main/resources/assets/textures/blocks/DolomiteSand.png b/src/main/resources/assets/textures/blocks/DolomiteSand.png new file mode 100644 index 0000000..b419bcf Binary files /dev/null and b/src/main/resources/assets/textures/blocks/DolomiteSand.png differ diff --git a/src/main/resources/assets/textures/blocks/EclogiteCracked.png b/src/main/resources/assets/textures/blocks/EclogiteCracked.png new file mode 100644 index 0000000..585efcf Binary files /dev/null and b/src/main/resources/assets/textures/blocks/EclogiteCracked.png differ diff --git a/src/main/resources/assets/textures/blocks/EclogiteGravel.png b/src/main/resources/assets/textures/blocks/EclogiteGravel.png new file mode 100644 index 0000000..9e72e13 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/EclogiteGravel.png differ diff --git a/src/main/resources/assets/textures/blocks/EclogiteMonolith.png b/src/main/resources/assets/textures/blocks/EclogiteMonolith.png new file mode 100644 index 0000000..b5e61ff Binary files /dev/null and b/src/main/resources/assets/textures/blocks/EclogiteMonolith.png differ diff --git a/src/main/resources/assets/textures/blocks/EclogiteSand.png b/src/main/resources/assets/textures/blocks/EclogiteSand.png new file mode 100644 index 0000000..d00b06d Binary files /dev/null and b/src/main/resources/assets/textures/blocks/EclogiteSand.png differ diff --git a/src/main/resources/assets/textures/blocks/GabbroCracked.png b/src/main/resources/assets/textures/blocks/GabbroCracked.png new file mode 100644 index 0000000..5388eb3 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/GabbroCracked.png differ diff --git a/src/main/resources/assets/textures/blocks/GabbroGravel.png b/src/main/resources/assets/textures/blocks/GabbroGravel.png new file mode 100644 index 0000000..0a1038b Binary files /dev/null and b/src/main/resources/assets/textures/blocks/GabbroGravel.png differ diff --git a/src/main/resources/assets/textures/blocks/GabbroMonolith.png b/src/main/resources/assets/textures/blocks/GabbroMonolith.png new file mode 100644 index 0000000..4ef7045 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/GabbroMonolith.png differ diff --git a/src/main/resources/assets/textures/blocks/GabbroSand.png b/src/main/resources/assets/textures/blocks/GabbroSand.png new file mode 100644 index 0000000..b562d38 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/GabbroSand.png differ diff --git a/src/main/resources/assets/textures/blocks/GraniteCracked.png b/src/main/resources/assets/textures/blocks/GraniteCracked.png deleted file mode 100644 index 508a193..0000000 Binary files a/src/main/resources/assets/textures/blocks/GraniteCracked.png and /dev/null differ diff --git a/src/main/resources/assets/textures/blocks/GraniteGravel.png b/src/main/resources/assets/textures/blocks/GraniteGravel.png deleted file mode 100644 index 7d7e35b..0000000 Binary files a/src/main/resources/assets/textures/blocks/GraniteGravel.png and /dev/null differ diff --git a/src/main/resources/assets/textures/blocks/LimestoneCracked.png b/src/main/resources/assets/textures/blocks/LimestoneCracked.png new file mode 100644 index 0000000..588f836 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/LimestoneCracked.png differ diff --git a/src/main/resources/assets/textures/blocks/LimestoneGravel.png b/src/main/resources/assets/textures/blocks/LimestoneGravel.png new file mode 100644 index 0000000..d5229d7 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/LimestoneGravel.png differ diff --git a/src/main/resources/assets/textures/blocks/LimestoneMonolith.png b/src/main/resources/assets/textures/blocks/LimestoneMonolith.png new file mode 100644 index 0000000..e644446 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/LimestoneMonolith.png differ diff --git a/src/main/resources/assets/textures/blocks/LimestoneSand.png b/src/main/resources/assets/textures/blocks/LimestoneSand.png new file mode 100644 index 0000000..2dec5bd Binary files /dev/null and b/src/main/resources/assets/textures/blocks/LimestoneSand.png differ diff --git a/src/main/resources/assets/textures/blocks/MarbleCracked.png b/src/main/resources/assets/textures/blocks/MarbleCracked.png new file mode 100644 index 0000000..b1bd018 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/MarbleCracked.png differ diff --git a/src/main/resources/assets/textures/blocks/MarbleGravel.png b/src/main/resources/assets/textures/blocks/MarbleGravel.png new file mode 100644 index 0000000..5ef8d57 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/MarbleGravel.png differ diff --git a/src/main/resources/assets/textures/blocks/MarbleMonolith.png b/src/main/resources/assets/textures/blocks/MarbleMonolith.png new file mode 100644 index 0000000..dc666dc Binary files /dev/null and b/src/main/resources/assets/textures/blocks/MarbleMonolith.png differ diff --git a/src/main/resources/assets/textures/blocks/MarbleSand.png b/src/main/resources/assets/textures/blocks/MarbleSand.png new file mode 100644 index 0000000..a2738e3 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/MarbleSand.png differ diff --git a/src/main/resources/assets/textures/blocks/RedGraniteCracked.png b/src/main/resources/assets/textures/blocks/RedGraniteCracked.png new file mode 100644 index 0000000..2d4cb78 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/RedGraniteCracked.png differ diff --git a/src/main/resources/assets/textures/blocks/RedGraniteGravel.png b/src/main/resources/assets/textures/blocks/RedGraniteGravel.png new file mode 100644 index 0000000..077b14e Binary files /dev/null and b/src/main/resources/assets/textures/blocks/RedGraniteGravel.png differ diff --git a/src/main/resources/assets/textures/blocks/GraniteMonolith.png b/src/main/resources/assets/textures/blocks/RedGraniteMonolith.png similarity index 100% rename from src/main/resources/assets/textures/blocks/GraniteMonolith.png rename to src/main/resources/assets/textures/blocks/RedGraniteMonolith.png diff --git a/src/main/resources/assets/textures/blocks/RedGraniteSand.png b/src/main/resources/assets/textures/blocks/RedGraniteSand.png new file mode 100644 index 0000000..28abf60 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/RedGraniteSand.png differ diff --git a/src/main/resources/assets/textures/blocks/TemporaryLeaves.png b/src/main/resources/assets/textures/blocks/TemporaryLeaves.png new file mode 100644 index 0000000..938c740 Binary files /dev/null and b/src/main/resources/assets/textures/blocks/TemporaryLeaves.png differ diff --git a/src/main/resources/assets/textures/items/MoonTypeIceCream.png b/src/main/resources/assets/textures/items/MoonTypeIceCream.png new file mode 100644 index 0000000..a37c756 Binary files /dev/null and b/src/main/resources/assets/textures/items/MoonTypeIceCream.png differ diff --git a/src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java b/src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java new file mode 100644 index 0000000..ef3d4c3 --- /dev/null +++ b/src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java @@ -0,0 +1,83 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.generic; + +import static org.junit.Assert.fail; +import static ru.windcorp.progressia.common.world.generic.GenericChunks.*; + +import java.util.Random; + +import org.junit.Test; + +import glm.Glm; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.AbsFace; + +public class GenericChunkRotationsTest { + + private static void assertVecEquals(String message, AbsFace up, Vec3i a, Vec3i b) { + if (a == b) { + return; + } + + if (Glm.equals(a, b)) { + return; + } + + fail(String.format("%s. x = (%4d; %4d; %4d), got (%4d; %4d; %4d) (up = %s)", message, a.x, a.y, a.z, b.x, b.y, b.z, up)); + } + + private void check(int x, int y, int z) { + for (AbsFace up : AbsFace.getFaces()) { + + Vec3i veci = new Vec3i(x, y, z); + + assertVecEquals("Vec3i, x != resolve(relativize(x))", up, veci, resolve(relativize(veci, up, null), up, null)); + assertVecEquals("Vec3i, x != relativize(resolve(x))", up, veci, relativize(resolve(veci, up, null), up, null)); + + } + } + + @Test + public void specialCases() { + + for (int x = -1; x <= 1; ++x) { + for (int y = -1; y <= 1; ++y) { + for (int z = -1; z <= 1; ++z) { + check(x, y, z); + } + } + } + + } + + @Test + public void randomValues() { + + final int iterations = 2 << 16; + final long seed = 0; + + Random random = new Random(seed); + + for (int i = 0; i < iterations; ++i) { + check(random.nextInt(200) - 100, random.nextInt(200) - 100, random.nextInt(200) - 100); + } + + } + +} diff --git a/src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java b/src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java new file mode 100644 index 0000000..27d6368 --- /dev/null +++ b/src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java @@ -0,0 +1,100 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.common.world.rels; + +import static org.junit.Assert.fail; +import static ru.windcorp.progressia.common.world.rels.AxisRotations.*; + +import java.util.Random; + +import org.junit.Test; + +import glm.Glm; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; + +public class AxisRotationsTest { + + private static void assertVecEquals(String message, AbsFace up, Vec3i a, Vec3i b) { + if (a == b) { + return; + } + + if (Glm.equals(a, b)) { + return; + } + + fail(String.format("%s. x = (%4d; %4d; %4d), got (%4d; %4d; %4d) (up = %s)", message, a.x, a.y, a.z, b.x, b.y, b.z, up)); + } + + private static void assertVecEquals(String message, AbsFace up, Vec3 a, Vec3 b) { + if (a == b) { + return; + } + + if (b.sub_(a).length() <= 1e-3) { + return; + } + + fail(String.format("%s. x = (%4f; %4f; %4f), got (%4f; %4f; %4f), d = %f (up = %s)", message, a.x, a.y, a.z, b.x, b.y, b.z, b.sub_(a).length(), up)); + } + + private void check(int x, int y, int z) { + for (AbsFace up : AbsFace.getFaces()) { + + Vec3i veci = new Vec3i(x, y, z); + + assertVecEquals("Vec3i, x != resolve(relativize(x))", up, veci, resolve(relativize(veci, up, null), up, null)); + assertVecEquals("Vec3i, x != relativize(resolve(x))", up, veci, relativize(resolve(veci, up, null), up, null)); + + Vec3 vecf = new Vec3(x, y, z); + + assertVecEquals("Vec3, x != resolve(relativize(x))", up, vecf, resolve(relativize(vecf, up, null), up, null)); + assertVecEquals("Vec3, x != relativize(resolve(x))", up, vecf, relativize(resolve(vecf, up, null), up, null)); + + } + } + + @Test + public void specialCases() { + + for (int x = -1; x <= 1; ++x) { + for (int y = -1; y <= 1; ++y) { + for (int z = -1; z <= 1; ++z) { + check(x, y, z); + } + } + } + + } + + @Test + public void randomValues() { + + final int iterations = 2 << 16; + final long seed = 0; + + Random random = new Random(seed); + + for (int i = 0; i < iterations; ++i) { + check(random.nextInt(200) - 100, random.nextInt(200) - 100, random.nextInt(200) - 100); + } + + } + +}