diff --git a/src/api/java/com/minelittlepony/render/model/GlowRenderer.java b/src/api/java/com/minelittlepony/render/model/GlowRenderer.java new file mode 100644 index 00000000..0e9becb5 --- /dev/null +++ b/src/api/java/com/minelittlepony/render/model/GlowRenderer.java @@ -0,0 +1,53 @@ +package com.minelittlepony.render.model; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.ModelBase; + +import org.lwjgl.opengl.GL11; + +import com.minelittlepony.util.render.AbstractBoxRenderer; +import com.minelittlepony.util.render.Color; + +public class GlowRenderer extends AbstractBoxRenderer { + + int tint; + float alpha = 1; + + public GlowRenderer(ModelBase model, int x, int y) { + super(model, x, y); + } + + public GlowRenderer setAlpha(float alpha) { + this.alpha = alpha; + + return this; + } + + public GlowRenderer setTint(int tint) { + this.tint = tint; + + return this; + } + + public void applyTint(float alpha) { + Color.glColor(tint, alpha); + } + + @Override + public void createBox(float offX, float offY, float offZ, int width, int height, int depth, float scaleFactor, boolean mirrored) { + cubeList.add(new ModelGlow(this, textureOffsetX, textureOffsetY, offX, offY, offZ, width, height, depth, scaleFactor, alpha)); + } + + @Override + public void render(float scale) { + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); + Minecraft.getMinecraft().entityRenderer.disableLightmap(); + super.render(scale); + GL11.glPopAttrib(); + } + + @Override + protected GlowRenderer copySelf() { + return new GlowRenderer(baseModel, textureOffsetX, textureOffsetY); + } +} diff --git a/src/api/java/com/minelittlepony/render/model/ModelGlow.java b/src/api/java/com/minelittlepony/render/model/ModelGlow.java new file mode 100644 index 00000000..54289295 --- /dev/null +++ b/src/api/java/com/minelittlepony/render/model/ModelGlow.java @@ -0,0 +1,78 @@ +package com.minelittlepony.render.model; + +import net.minecraft.client.renderer.BufferBuilder; + +import com.minelittlepony.util.render.Box; +import com.minelittlepony.util.render.Quad; +import com.minelittlepony.util.render.Vertex; + +/** + * Like a normal box, but with the top narrowed a bit. + */ +public class ModelGlow extends Box { + + private final float alpha; + + private Quad[] quadList; + + public ModelGlow(GlowRenderer renderer, int texX, int texY, float xMin, float yMin, float zMin, int w, int h, int d, float scale, float alpha) { + super(renderer, texX, texY, xMin, yMin, zMin, w, h, d, scale); + + this.alpha = alpha; + + float xMax = xMin + w + scale; + float yMax = yMin + h + scale; + float zMax = zMin + d + scale; + + xMin -= scale; + yMin -= scale; + zMin -= scale; + + if (renderer.mirror) { + float v = xMax; + xMax = xMin; + xMin = v; + } + + float tipInset = 0.4f; + + float tipXmin = xMin + w * tipInset; + float tipZmin = zMin + d * tipInset; + float tipXMax = xMax - w * tipInset; + float tipZMax = zMax - d * tipInset; + + // w:west e:east d:down u:up s:south n:north + Vertex wds = vert(tipXmin, yMin, tipZmin, 0, 0); + Vertex eds = vert(tipXMax, yMin, tipZmin, 0, 8); + Vertex eus = vert(xMax, yMax, zMin, 8, 8); + Vertex wus = vert(xMin, yMax, zMin, 8, 0); + Vertex wdn = vert(tipXmin, yMin, tipZMax, 0, 0); + Vertex edn = vert(tipXMax, yMin, tipZMax, 0, 8); + Vertex eun = vert(xMax, yMax, zMax, 8, 8); + Vertex wun = vert(xMin, yMax, zMax, 8, 0); + + quadList = new Quad[] { + quad(texX + d + w, d, texY + d, h, edn, eds, eus, eun), + quad(texX, d, texY + d, h, wds, wdn, wun, wus), + quad(texX + d, w, texY, d, edn, wdn, wds, eds), + quad(texX + d + w, w, texY + d, -d, eus, wus, wun, eun), + quad(texX + d, w, texY + d, h, eds, wds, wus, eus), + quad(texX + d + w + d, w, texY + d, h, wdn, edn, eun, wun) + }; + + if (renderer.mirror) { + for (Quad i : quadList) { + i.flipFace(); + } + } + } + + @Override + public void render(BufferBuilder buffer, float scale) { + parent.applyTint(alpha); + + for (Quad i : quadList) { + i.draw(buffer, scale); + } + } +} diff --git a/src/api/java/com/minelittlepony/render/model/ModelPlane.java b/src/api/java/com/minelittlepony/render/model/ModelPlane.java new file mode 100644 index 00000000..444325a2 --- /dev/null +++ b/src/api/java/com/minelittlepony/render/model/ModelPlane.java @@ -0,0 +1,84 @@ +package com.minelittlepony.render.model; + +import net.minecraft.client.renderer.BufferBuilder; + +import com.minelittlepony.util.render.Box; +import com.minelittlepony.util.render.Quad; +import com.minelittlepony.util.render.Vertex; + +import javax.annotation.Nonnull; + +public class ModelPlane extends Box { + + private Quad quad; + + public boolean hidden = false; + + public ModelPlane(PlaneRenderer renderer, int textureX, int textureY, float xMin, float yMin, float zMin, int w, int h, int d, float scale, Plane face) { + super(renderer, textureX, textureY, xMin, yMin, zMin, w, h, d, scale, false); + + float xMax = xMin + w + scale; + float yMax = yMin + h + scale; + float zMax = zMin + d + scale; + + xMin -= scale; + yMin -= scale; + zMin -= scale; + + if (renderer.mirror) { + float v = xMax; + xMax = xMin; + xMin = v; + } + + if (renderer.mirrory) { + float v = yMax; + yMax = yMin; + yMin = v; + } + + if (renderer.mirrorz) { + float v = zMax; + zMax = zMin; + zMin = v; + } + + // w:west e:east d:down u:up s:south n:north + Vertex wds = vert(xMin, yMin, zMin, 0, 0); + Vertex eds = vert(xMax, yMin, zMin, 0, 8); + Vertex eus = vert(xMax, yMax, zMin, 8, 8); + Vertex wus = vert(xMin, yMax, zMin, 8, 0); + Vertex wdn = vert(xMin, yMin, zMax, 0, 0); + Vertex edn = vert(xMax, yMin, zMax, 0, 8); + Vertex eun = vert(xMax, yMax, zMax, 8, 8); + Vertex wun = vert(xMin, yMax, zMax, 8, 0); + + if (face == Plane.EAST) { + quad = quad(textureX, d, textureY, h, edn, eds, eus, eun); + } + if (face == Plane.WEST) { + quad = quad(textureX, d, textureY, h, wds, wdn, wun, wus); + } + if (face == Plane.UP) { + quad = quad(textureX, w, textureY, d, edn, wdn, wds, eds); + } + if (face == Plane.DOWN) { + quad = quad(textureX, w, textureY, d, eus, wus, wun, eun); + } + if (face == Plane.SOUTH) { + quad = quad(textureX, w, textureY, h, eds, wds, wus, eus); + } + if (face == Plane.NORTH) { + quad = quad(textureX, w, textureY, h, wdn, edn, eun, wun); + } + + if (renderer.mirror || renderer.mirrory || renderer.mirrorz) { + quad.flipFace(); + } + } + + @Override + public void render(@Nonnull BufferBuilder buffer, float scale) { + if (!hidden) quad.draw(buffer, scale); + } +} diff --git a/src/api/java/com/minelittlepony/render/model/Plane.java b/src/api/java/com/minelittlepony/render/model/Plane.java new file mode 100644 index 00000000..9e509117 --- /dev/null +++ b/src/api/java/com/minelittlepony/render/model/Plane.java @@ -0,0 +1,10 @@ +package com.minelittlepony.render.model; + +enum Plane { + NORTH, + SOUTH, + UP, + DOWN, + EAST, + WEST +} \ No newline at end of file diff --git a/src/api/java/com/minelittlepony/render/model/PlaneRenderer.java b/src/api/java/com/minelittlepony/render/model/PlaneRenderer.java new file mode 100644 index 00000000..e738e396 --- /dev/null +++ b/src/api/java/com/minelittlepony/render/model/PlaneRenderer.java @@ -0,0 +1,69 @@ +package com.minelittlepony.render.model; + +import net.minecraft.client.model.ModelBase; + +import com.minelittlepony.util.render.AbstractBoxRenderer; + +public class PlaneRenderer extends AbstractBoxRenderer { + + public boolean mirrory, mirrorz; + + public PlaneRenderer(ModelBase model) { + super(model); + } + + public PlaneRenderer(ModelBase model, int x, int y) { + super(model, x, y); + } + + /** + * Flips the Z bit. Any calls to add a plane will be mirrored until this is called again. + */ + public PlaneRenderer flipZ() { + mirrorz = !mirrorz; + return this; + } + + + /** + * Flips the Y bit. Any calls to add a plane will be mirrored until this is called again. + */ + public PlaneRenderer flipY() { + mirrory = !mirrory; + return this; + } + + @Override + protected PlaneRenderer copySelf() { + return new PlaneRenderer(baseModel, textureOffsetX, textureOffsetY); + } + + private PlaneRenderer addPlane(float offX, float offY, float offZ, int width, int height, int depth, float scale, Plane face) { + cubeList.add(new ModelPlane(this, textureOffsetX, textureOffsetY, modelOffsetX + offX, modelOffsetY + offY, modelOffsetZ + offZ, width, height, depth, scale, face)); + return this; + } + + public PlaneRenderer top(float offX, float offY, float offZ, int width, int depth, float scale) { + return addPlane(offX, offY, offZ, width, 0, depth, scale, Plane.UP); + } + + public PlaneRenderer bottom(float offX, float offY, float offZ, int width, int depth, float scale) { + return addPlane(offX, offY, offZ, width, 0, depth, scale, Plane.DOWN); + } + + public PlaneRenderer west(float offX, float offY, float offZ, int height, int depth, float scale) { + return addPlane(offX, offY, offZ, 0, height, depth, scale, Plane.WEST); + } + + public PlaneRenderer east(float offX, float offY, float offZ, int height, int depth, float scale) { + return addPlane(offX, offY, offZ, 0, height, depth, scale, Plane.EAST); + } + + public PlaneRenderer north(float offX, float offY, float offZ, int width, int height, float scale) { + return addPlane(offX, offY, offZ - scale * 2, width, height, 0, scale, Plane.NORTH); + } + + public PlaneRenderer south(float offX, float offY, float offZ, int width, int height, float scale) { + return addPlane(offX, offY, offZ + scale * 2, width, height, 0, scale, Plane.SOUTH); + } +} diff --git a/src/api/java/com/minelittlepony/render/model/PonyRenderer.java b/src/api/java/com/minelittlepony/render/model/PonyRenderer.java new file mode 100644 index 00000000..d656eb10 --- /dev/null +++ b/src/api/java/com/minelittlepony/render/model/PonyRenderer.java @@ -0,0 +1,21 @@ +package com.minelittlepony.render.model; + +import net.minecraft.client.model.ModelBase; + +import com.minelittlepony.util.render.AbstractBoxRenderer; + +public class PonyRenderer extends AbstractBoxRenderer { + + public PonyRenderer(ModelBase model) { + super(model); + } + + public PonyRenderer(ModelBase model, int texX, int texY) { + super(model, texX, texY); + } + + @Override + protected PonyRenderer copySelf() { + return new PonyRenderer(baseModel, textureOffsetX, textureOffsetY); + } +} diff --git a/src/api/java/com/minelittlepony/render/model/package-info.java b/src/api/java/com/minelittlepony/render/model/package-info.java new file mode 100644 index 00000000..79bb8ff0 --- /dev/null +++ b/src/api/java/com/minelittlepony/render/model/package-info.java @@ -0,0 +1,7 @@ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package com.minelittlepony.render.model; + +import mcp.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/api/java/com/minelittlepony/util/render/AbstractBoxRenderer.java b/src/api/java/com/minelittlepony/util/render/AbstractBoxRenderer.java new file mode 100644 index 00000000..2bce7b9b --- /dev/null +++ b/src/api/java/com/minelittlepony/util/render/AbstractBoxRenderer.java @@ -0,0 +1,212 @@ +package com.minelittlepony.util.render; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelBox; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.client.model.TextureOffset; + +@SuppressWarnings("unchecked") +public abstract class AbstractBoxRenderer> extends ModelRenderer { + + protected final ModelBase baseModel; + + protected int textureOffsetX; + protected int textureOffsetY; + + protected float modelOffsetX; + protected float modelOffsetY; + protected float modelOffsetZ; + + public AbstractBoxRenderer(ModelBase model) { + super(model); + baseModel = model; + } + + public AbstractBoxRenderer(ModelBase model, int texX, int texY) { + super(model, texX, texY); + baseModel = model; + } + + /** + * Called to create a new instance of this renderer (used for child renderers) + */ + protected abstract T copySelf(); + + @Override + public T setTextureOffset(int x, int y) { + this.textureOffsetX = x; + this.textureOffsetY = y; + super.setTextureOffset(x, y); + return (T) this; + } + + /** + * Flips the mirror flag. All faces are mirrored until this is called again. + */ + public T flip() { + return mirror(!mirror); + } + + public T mirror(boolean m) { + mirror = m; + return (T) this; + } + + /** + * Sets the texture offset + */ + public T tex(int x, int y) { + return setTextureOffset(x, y); + } + + /** + * Sets the texture size for this renderer. + */ + public T size(int w, int h) { + return (T) setTextureSize(w, h); + } + + /** + * Positions this model in space. + */ + public T at(float x, float y, float z) { + return (T)at(this, x, y, z); + } + + /** + * Sets an offset to be used on all shapes and children created through this renderer. + */ + public T offset(float x, float y, float z) { + modelOffsetX = x; + modelOffsetY = y; + modelOffsetZ = z; + return (T) this; + } + + /** + * Adjusts the rotation center of the given renderer by the given amounts in each direction. + */ + public static void shiftRotationPoint(ModelRenderer renderer, float x, float y, float z) { + renderer.rotationPointX += x; + renderer.rotationPointY += y; + renderer.rotationPointZ += z; + } + + /** + * Sets this renderer's rotation angles. + */ + public T rotate(float x, float y, float z) { + rotateAngleX = x; + rotateAngleY = y; + rotateAngleZ = z; + return (T) this; + } + + /** + * Positions a given model in space by setting its offset values divided + * by 16 to account for scaling applied inside the model. + */ + public static T at(T renderer, float x, float y, float z) { + renderer.offsetX = x / 16; + renderer.offsetY = y / 16; + renderer.offsetZ = z / 16; + return renderer; + } + + /** + * Rotates this model to align itself with the angles of another. + */ + public void rotateTo(ModelRenderer other) { + rotate(other.rotateAngleX, other.rotateAngleY, other.rotateAngleZ); + } + + /** + * Shifts this model to align its center with the center of another. + */ + public T rotateAt(ModelRenderer other) { + return around(other.rotationPointX, other.rotationPointY, other.rotationPointZ); + } + + /** + * Sets the rotation point. + */ + public T around(float x, float y, float z) { + setRotationPoint(x, y, z); + return (T) this; + } + + /** + * Gets or creates a new child model based on its unique index. + * New children will be of the same type and inherit the same textures and offsets of the original. + */ + public T child(int index) { + if (childModels == null || index >= childModels.size()) { + return child(); + } + return (T)childModels.get(index); + } + + /** + * Returns a brand new child under this renderer. + */ + public T child() { + T copy = copySelf(); + child(copy.offset(modelOffsetX, modelOffsetY, modelOffsetZ)); + copy.textureHeight = textureHeight; + copy.textureWidth = textureWidth; + return copy; + } + + /** + * Adds a new child renderer and returns itself for chaining. + */ + public T child(K child) { + addChild(child); + return (T)this; + } + + @Override + public T addBox(String partName, float offX, float offY, float offZ, int width, int height, int depth) { + partName = boxName + "." + partName; + + TextureOffset tex = baseModel.getTextureOffset(partName); + + setTextureOffset(tex.textureOffsetX, tex.textureOffsetY).addBox(offX, offY, offZ, width, height, depth); + cubeList.get(cubeList.size() - 1).setBoxName(partName); + + return (T) this; + } + + @Override + public T addBox(float offX, float offY, float offZ, int width, int height, int depth) { + addBox(offX, offY, offZ, width, height, depth, 0); + return (T) this; + } + + @Override + public T addBox(float offX, float offY, float offZ, int width, int height, int depth, boolean mirrored) { + addBox(offX, offY, offZ, width, height, depth, 0, mirrored); + return (T)this; + } + + @Override + public void addBox(float offX, float offY, float offZ, int width, int height, int depth, float scaleFactor) { + addBox(offX, offY, offZ, width, height, depth, scaleFactor, mirror); + } + + /** + * Creates a textured box. + */ + public T box(float offX, float offY, float offZ, int width, int height, int depth, float scaleFactor) { + return addBox(offX, offY, offZ, width, height, depth, scaleFactor, mirror); + } + + private T addBox(float offX, float offY, float offZ, int width, int height, int depth, float scaleFactor, boolean mirrored) { + createBox(modelOffsetX + offX, modelOffsetY + offY, modelOffsetZ + offZ, width, height, depth, scaleFactor, mirrored); + return (T)this; + } + + protected void createBox(float offX, float offY, float offZ, int width, int height, int depth, float scaleFactor, boolean mirrored) { + cubeList.add(new ModelBox(this, textureOffsetX, textureOffsetY, offX, offY, offZ, width, height, depth, scaleFactor, mirrored)); + } +} diff --git a/src/api/java/com/minelittlepony/util/render/Box.java b/src/api/java/com/minelittlepony/util/render/Box.java new file mode 100644 index 00000000..0c4ad8f6 --- /dev/null +++ b/src/api/java/com/minelittlepony/util/render/Box.java @@ -0,0 +1,36 @@ +package com.minelittlepony.util.render; + +import net.minecraft.client.model.ModelBox; +import net.minecraft.client.model.ModelRenderer; + +public abstract class Box extends ModelBox { + + protected final T parent; + + public Box(T renderer, int texU, int texV, float x, float y, float z, int dx, int dy, int dz, float delta) { + super(renderer, texU, texV, x, y, z, dx, dy, dz, delta); + parent = renderer; + } + + public Box(T renderer, int texU, int texV, float x, float y, float z, int dx, int dy, int dz, float delta, boolean mirror) { + super(renderer, texU, texV, x, y, z, dx, dy, dz, delta, mirror); + parent = renderer; + } + + /** + * Creates a new vertex mapping the given (x, y, z) coordinates to a texture offset. + */ + protected Vertex vert(float x, float y, float z, int texX, int texY) { + return new Vertex(x, y, z, texX, texY); + } + + /** + * Creates a new quad with the given spacial vertices. + */ + protected Quad quad(int startX, int width, int startY, int height, Vertex ...verts) { + return new Quad(verts, + startX, startY, + startX + width, startY + height, + parent.textureWidth, parent.textureHeight); + } +} \ No newline at end of file diff --git a/src/api/java/com/minelittlepony/util/render/Color.java b/src/api/java/com/minelittlepony/util/render/Color.java new file mode 100644 index 00000000..967e061b --- /dev/null +++ b/src/api/java/com/minelittlepony/util/render/Color.java @@ -0,0 +1,21 @@ +package com.minelittlepony.util.render; + +import net.minecraft.client.renderer.GlStateManager; + +public interface Color { + static float r(int color) { + return (color >> 16 & 255) / 255F; + } + + static float g(int color) { + return (color >> 8 & 255) / 255F; + } + + static float b(int color) { + return (color & 255) / 255F; + } + + static void glColor(int color, float alpha) { + GlStateManager.color(Color.r(color), Color.g(color), Color.b(color), alpha); + } +} diff --git a/src/api/java/com/minelittlepony/util/render/ITextureSupplier.java b/src/api/java/com/minelittlepony/util/render/ITextureSupplier.java new file mode 100644 index 00000000..ce4dc3f2 --- /dev/null +++ b/src/api/java/com/minelittlepony/util/render/ITextureSupplier.java @@ -0,0 +1,11 @@ +package com.minelittlepony.util.render; + +import net.minecraft.util.ResourceLocation; + +/** + * A texture pool for generating multiple associated textures. + */ +@FunctionalInterface +public interface ITextureSupplier { + ResourceLocation supplyTexture(T key); +} diff --git a/src/api/java/com/minelittlepony/util/render/Quad.java b/src/api/java/com/minelittlepony/util/render/Quad.java new file mode 100644 index 00000000..217ac3ae --- /dev/null +++ b/src/api/java/com/minelittlepony/util/render/Quad.java @@ -0,0 +1,37 @@ +package com.minelittlepony.util.render; + +import net.minecraft.client.model.TexturedQuad; + +public class Quad extends TexturedQuad { + + Quad(Vertex[] vertices, int texcoordU1, int texcoordV1, int texcoordU2, int texcoordV2, float textureWidth, float textureHeight) { + super(vertices, texcoordU1, texcoordV1, texcoordU2, texcoordV2, textureWidth, textureHeight); + } + + /** + * Reverses the order of the vertices belonging to this quad. + * Positions of the vertices stay the same but the order of rendering is reversed to go counter-clockwise. + * + * Reversal also affects the cross-product used to calculate texture orientation. + *
+     * Normal:
+     * 0-----1
+     * |\    |
+     * |  \  |
+     * |    \|
+     * 3-----2
+     *
+     * After flipFace:
+     *
+     * 3-----2
+     * |    /|
+     * |  /  |
+     * |/    |
+     * 0-----1
+     * 
+ */ + @Override + public void flipFace() { + super.flipFace(); + } +} \ No newline at end of file diff --git a/src/api/java/com/minelittlepony/util/render/Vertex.java b/src/api/java/com/minelittlepony/util/render/Vertex.java new file mode 100644 index 00000000..dbfb36e3 --- /dev/null +++ b/src/api/java/com/minelittlepony/util/render/Vertex.java @@ -0,0 +1,21 @@ +package com.minelittlepony.util.render; + +import net.minecraft.client.model.PositionTextureVertex; + +public class Vertex extends PositionTextureVertex { + + public Vertex(float x, float y, float z, float texX, float texY) { + super(x, y, z, texX, texY); + } + + private Vertex(Vertex old, float texX, float texY) { + super(old, texX, texY); + } + + // The MCP name is misleading. + // This is meant to return a COPY with the given texture position + @Override + public Vertex setTexturePosition(float texX, float texY) { + return new Vertex(this, texX, texY); + } +} diff --git a/src/api/java/com/minelittlepony/util/render/package-info.java b/src/api/java/com/minelittlepony/util/render/package-info.java new file mode 100644 index 00000000..4e9d3c08 --- /dev/null +++ b/src/api/java/com/minelittlepony/util/render/package-info.java @@ -0,0 +1,7 @@ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package com.minelittlepony.util.render; + +import mcp.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/minelittlepony/render/model/ModelQuads.java b/src/main/java/com/minelittlepony/render/model/ModelQuads.java new file mode 100644 index 00000000..a8aadb84 --- /dev/null +++ b/src/main/java/com/minelittlepony/render/model/ModelQuads.java @@ -0,0 +1,32 @@ +package com.minelittlepony.render.model; + +import java.util.ArrayList; +import java.util.List; + +import com.minelittlepony.util.render.Box; + +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.client.model.PositionTextureVertex; +import net.minecraft.client.model.TexturedQuad; +import net.minecraft.client.renderer.BufferBuilder; + +public class ModelQuads extends Box { + + public ModelQuads(ModelRenderer renderer) { + super(renderer, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + + protected List quadList = new ArrayList(); + + public ModelQuads addFace(PositionTextureVertex... vertices) { + quadList.add(new TexturedShape2d(vertices)); + + return this; + } + + public void render(BufferBuilder renderer, float scale) { + for (TexturedQuad i : quadList) { + i.draw(renderer, scale); + } + } +} diff --git a/src/main/java/com/minelittlepony/render/model/TexturedShape2d.java b/src/main/java/com/minelittlepony/render/model/TexturedShape2d.java new file mode 100644 index 00000000..e4925713 --- /dev/null +++ b/src/main/java/com/minelittlepony/render/model/TexturedShape2d.java @@ -0,0 +1,50 @@ +package com.minelittlepony.render.model; + +import net.minecraft.client.model.PositionTextureVertex; +import net.minecraft.client.model.TexturedQuad; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.math.Vec3d; + +public class TexturedShape2d extends TexturedQuad { + + protected boolean invertNormal; + + public TexturedShape2d(PositionTextureVertex... vertices) { + super(vertices); + } + + public TexturedShape2d(PositionTextureVertex[] vertices, int texcoordU1, int texcoordV1, int texcoordU2, int texcoordV2, float textureWidth, float textureHeight) { + super(vertices, texcoordU1, texcoordV1, texcoordU2, texcoordV2, textureWidth, textureHeight); + } + + public TexturedShape2d setInvertNormal() { + invertNormal = true; + return this; + } + + public void drawQuad(BufferBuilder renderer, float scale) { + Vec3d vec3d = vertexPositions[1].vector3D.subtractReverse(vertexPositions[0].vector3D); + Vec3d vec3d1 = vertexPositions[1].vector3D.subtractReverse(vertexPositions[2].vector3D); + Vec3d vec3d2 = vec3d1.crossProduct(vec3d).normalize(); + float f = (float)vec3d2.x; + float f1 = (float)vec3d2.y; + float f2 = (float)vec3d2.z; + + if (invertNormal) { + f = -f; + f1 = -f1; + f2 = -f2; + } + + renderer.begin(7, DefaultVertexFormats.OLDMODEL_POSITION_TEX_NORMAL); + + for (int i = 0; i < nVertices; ++i) { + PositionTextureVertex positiontexturevertex = vertexPositions[i]; + renderer.pos(positiontexturevertex.vector3D.x * (double)scale, positiontexturevertex.vector3D.y * (double)scale, positiontexturevertex.vector3D.z * (double)scale).tex((double)positiontexturevertex.texturePositionX, (double)positiontexturevertex.texturePositionY).normal(f, f1, f2).endVertex(); + } + + Tessellator.getInstance().draw(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/UEntities.java b/src/main/java/com/minelittlepony/unicopia/UEntities.java index 8c2baa5d..dcaaae20 100644 --- a/src/main/java/com/minelittlepony/unicopia/UEntities.java +++ b/src/main/java/com/minelittlepony/unicopia/UEntities.java @@ -3,9 +3,12 @@ package com.minelittlepony.unicopia; import com.minelittlepony.unicopia.entity.EntityCloud; import com.minelittlepony.unicopia.entity.EntityConstructionCloud; import com.minelittlepony.unicopia.entity.EntityRacingCloud; +import com.minelittlepony.unicopia.entity.EntitySpell; import com.minelittlepony.unicopia.entity.EntityWildCloud; import com.minelittlepony.unicopia.render.RenderCloud; +import com.minelittlepony.unicopia.render.RenderGem; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityList.EntityEggInfo; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.client.registry.RenderingRegistry; @@ -13,22 +16,29 @@ import net.minecraftforge.fml.common.registry.EntityEntry; import net.minecraftforge.registries.IForgeRegistry; public class UEntities { - private static final int BRUSHES_ROYALBLUE = 4286945; - private static final int BRUSHES_CHARTREUSE = 8388352; + private static final int BRUSHES_ROYALBLUE = 0x4169E1; + private static final int BRUSHES_CHARTREUSE = 0x7FFF00; static void init(IForgeRegistry registry) { - EntityEntry entry = new EntityEntry(EntityCloud.class, "cloud").setRegistryName(Unicopia.MODID, "cloud"); + addEntity(registry, EntityCloud.class, "cloud", true, BRUSHES_ROYALBLUE, BRUSHES_CHARTREUSE); + addEntity(registry, EntityWildCloud.class, "wild_cloud", false, 0, 0); + addEntity(registry, EntityRacingCloud.class, "racing_cloud", false, 0, 0); + addEntity(registry, EntityConstructionCloud.class, "construction_cloud", false, 0, 0); + addEntity(registry, EntitySpell.class, "magic_spell", false, 0, 0); + } - entry.setEgg(new EntityEggInfo(new ResourceLocation("unicopia", "cloud"), BRUSHES_ROYALBLUE, BRUSHES_CHARTREUSE)); + static void addEntity(IForgeRegistry registry, Class type, String name, boolean egg, int a, int b) { + EntityEntry entry = new EntityEntry(type, name).setRegistryName(Unicopia.MODID, name); + + if (egg) { + entry.setEgg(new EntityEggInfo(new ResourceLocation("unicopia", "cloud"), a, a)); + } registry.register(entry); - - registry.register(new EntityEntry(EntityWildCloud.class, "wild_cloud").setRegistryName(Unicopia.MODID, "wild_cloud")); - registry.register(new EntityEntry(EntityRacingCloud.class, "racing_cloud").setRegistryName(Unicopia.MODID, "racing_cloud")); - registry.register(new EntityEntry(EntityConstructionCloud.class, "construction_cloud").setRegistryName(Unicopia.MODID, "construction_cloud")); } static void preInit() { RenderingRegistry.registerEntityRenderingHandler(EntityCloud.class, manager -> new RenderCloud(manager)); + RenderingRegistry.registerEntityRenderingHandler(EntitySpell.class, manager -> new RenderGem(manager)); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntitySpell.java b/src/main/java/com/minelittlepony/unicopia/entity/EntitySpell.java new file mode 100644 index 00000000..89a75acd --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntitySpell.java @@ -0,0 +1,308 @@ +package com.minelittlepony.unicopia.entity; + +import com.minelittlepony.unicopia.Predicates; +import com.minelittlepony.unicopia.UItems; +import com.minelittlepony.unicopia.item.ItemSpell; +import com.minelittlepony.unicopia.network.EffectSync; +import com.minelittlepony.unicopia.spell.ICaster; +import com.minelittlepony.unicopia.spell.IMagicEffect; +import com.minelittlepony.unicopia.spell.SpellRegistry; + +import net.minecraft.block.SoundType; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.datasync.DataParameter; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class EntitySpell extends EntityLiving implements IMagicals, ICaster { + + private EntityLivingBase owner = null; + + public float hoverStart; + + private static final DataParameter LEVEL = EntityDataManager + .createKey(EntitySpell.class, DataSerializers.VARINT); + + private static final DataParameter OWNER = EntityDataManager + .createKey(EntitySpell.class, DataSerializers.STRING); + + private static final DataParameter EFFECT = EntityDataManager + .createKey(EntitySpell.class, DataSerializers.COMPOUND_TAG); + + private final EffectSync effectDelegate = new EffectSync<>(this, EFFECT); + + public EntitySpell(World w) { + super(w); + setSize(0.6f, 0.25f); + hoverStart = (float)(Math.random() * Math.PI * 2.0D); + setRenderDistanceWeight(getRenderDistanceWeight() + 1); + preventEntitySpawning = false; + enablePersistence(); + } + + public boolean isInRangeToRenderDist(double distance) { + return super.isInRangeToRenderDist(distance); + } + + public void setEffect(IMagicEffect effect) { + effectDelegate.set(effect); + } + + public IMagicEffect getEffect() { + return effectDelegate.get(); + } + + @Override + protected void entityInit() { + super.entityInit(); + dataManager.register(LEVEL, 0); + dataManager.register(EFFECT, new NBTTagCompound()); + dataManager.register(OWNER, ""); + } + + public ItemStack onPlayerMiddleClick(EntityPlayer player) { + ItemStack stack = new ItemStack(UItems.spell, 1); + SpellRegistry.instance().enchantStack(stack, getEffect().getName()); + return stack; + } + + @Override + protected boolean canTriggerWalking() { + return false; + } + + @Override + public boolean isPushedByWater() { + return false; + } + + @Override + public boolean canRenderOnFire() { + return false; + } + + @Override + public void setOwner(EntityLivingBase owner) { + this.owner = owner; + setOwner(owner.getName()); + } + + protected void setOwner(String ownerName) { + if (ownerName != null && ownerName.length() != 0) { + dataManager.set(OWNER, ownerName); + } + } + + protected String getOwnerName() { + String ownerName = dataManager.get(OWNER); + + if (ownerName == null || ownerName.length() == 0) { + if (owner instanceof EntityPlayer) { + return owner.getName(); + } + + return ""; + } + + return ownerName; + } + + @Override + public EntityLivingBase getOwner() { + if (owner == null) { + String ownerName = dataManager.get(OWNER); + if (ownerName != null && ownerName.length() > 0) { + owner = world.getPlayerEntityByName(ownerName); + } + } + + return owner; + } + + protected void displayTick() { + if (hasEffect()) { + getEffect().renderAt(this, world, posX, posY, posZ, getLevel()); + } + } + + @Override + public void onUpdate() { + if (world.isRemote) { + displayTick(); + } + + if (getEffect() == null) { + setDead(); + } else { + if (getEffect().getDead()) { + setDead(); + onDeath(); + } else { + getEffect().updateAt(this, world, posX, posY, posZ, getLevel()); + } + + if (getEffect().allowAI()) { + super.onUpdate(); + } + } + } + + @Override + public void fall(float distance, float damageMultiplier) { + + } + + @Override + protected void updateFallState(double y, boolean onGround, IBlockState state, BlockPos pos) { + this.onGround = true; + //super.updateFallState(y, onGround = this.onGround = true, state, pos); + } + + public boolean attackEntityFrom(DamageSource source, float amount) { + if (!world.isRemote) { + setDead(); + onDeath(); + } + return false; + } + + protected void onDeath() { + SoundType sound = SoundType.STONE; + + world.playSound(posX, posY, posZ, sound.getBreakSound(), SoundCategory.NEUTRAL, sound.getVolume(), sound.getPitch(), true); + + if (world.getGameRules().getBoolean("doTileDrops")) { + int level = getLevel(); + + ItemStack stack = new ItemStack(UItems.spell, level + 1); + if (hasEffect()) { + SpellRegistry.instance().enchantStack(stack, getEffect().getName()); + } + + entityDropItem(stack, 0); + } + } + + public void setDead() { + if (hasEffect()) { + getEffect().setDead(); + } + super.setDead(); + } + + public int getLevel() { + return dataManager.get(LEVEL); + } + + public void setLevel(int radius) { + dataManager.set(LEVEL, radius); + } + + public boolean tryLevelUp(ItemStack stack) { + + if (SpellRegistry.stackHasEnchantment(stack)) { + if (!getEffect().getName().equals(SpellRegistry.getKeyFromStack(stack))) { + return false; + } + + increaseLevel(); + + if (!world.isRemote) { + if ((rand.nextFloat() * getLevel()) > 10 || overLevelCap()) { + world.createExplosion(this, posX, posY, posZ, getLevel()/2, true); + setDead(); + return false; + } + } + + playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1f, 1); + + return true; + } + return false; + } + + public EnumActionResult applyPlayerInteraction(EntityPlayer player, Vec3d vec, EnumHand hand) { + if (Predicates.MAGI.test(player)) { + ItemStack currentItem = player.getHeldItem(EnumHand.MAIN_HAND); + + if (currentItem != null && currentItem.getItem() instanceof ItemSpell) { + tryLevelUp(currentItem); + + if (!player.capabilities.isCreativeMode) { + currentItem.shrink(1); + + if (currentItem.isEmpty()) { + player.renderBrokenItemStack(currentItem); + } + } + + return EnumActionResult.SUCCESS; + } + } + + return EnumActionResult.FAIL; + } + + public void increaseLevel() { + setLevel(getLevel() + 1); + } + + public boolean canLevelUp() { + int max = getEffect().getMaxLevel(); + return max < 0 || getLevel() < max; + } + + public boolean overLevelCap() { + int max = getEffect().getMaxLevel(); + return max > 0 && getLevel() >= (max * 1.1); + } + + public void decreaseLevel() { + int level = getLevel() - 1; + if (level < 0) level = 0; + setLevel(level); + } + + @Override + public Entity getEntity() { + return this; + } + + @Override + public void readEntityFromNBT(NBTTagCompound compound) { + super.readEntityFromNBT(compound); + setOwner(compound.getString("ownerName")); + setLevel(compound.getInteger("level")); + + if (compound.hasKey("effect")) { + setEffect(SpellRegistry.instance().createEffectFromNBT(compound.getCompoundTag("effect"))); + } + } + + @Override + public void writeEntityToNBT(NBTTagCompound compound) { + super.writeEntityToNBT(compound); + + compound.setString("ownerName", getOwnerName()); + compound.setInteger("level", getLevel()); + + if (hasEffect()) { + compound.setTag("effect", SpellRegistry.instance().serializeEffectToNBT(getEffect())); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/entity/IMagicals.java b/src/main/java/com/minelittlepony/unicopia/entity/IMagicals.java new file mode 100644 index 00000000..ca27aaa7 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/IMagicals.java @@ -0,0 +1,7 @@ +package com.minelittlepony.unicopia.entity; + +import net.minecraft.entity.passive.IAnimals; + +public interface IMagicals extends IAnimals { + +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemSpell.java b/src/main/java/com/minelittlepony/unicopia/item/ItemSpell.java index 26cde6d6..0b5b3061 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ItemSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemSpell.java @@ -1,6 +1,7 @@ package com.minelittlepony.unicopia.item; import com.minelittlepony.unicopia.Predicates; +import com.minelittlepony.unicopia.entity.EntitySpell; import com.minelittlepony.unicopia.spell.IMagicEffect; import com.minelittlepony.unicopia.spell.IUseAction; import com.minelittlepony.unicopia.spell.SpellCastResult; @@ -43,8 +44,9 @@ public class ItemSpell extends Item implements ICastable { } if (dispenceResult == SpellCastResult.PLACE) { + BlockPos pos = source.getBlockPos(); - // castContainedSpell(source.getWorld(), pos.getX(), pos.getY(), pos.getZ(), stack, effect); + castContainedSpell(source.getWorld(), pos, stack, effect); stack.shrink(1); } @@ -114,7 +116,7 @@ public class ItemSpell extends Item implements ICastable { pos = pos.offset(side); if (result == SpellCastResult.PLACE) { - // castContainedSpell(world, pos.getX(), pos.getY(), pos.getZ(), stack, effect).setOwner(player); + castContainedSpell(world, pos, stack, effect).setOwner(player); } } @@ -169,11 +171,13 @@ public class ItemSpell extends Item implements ICastable { return result; } -/* protected static EntitySpell castContainedSpell(World world, int x, int y, int z, ItemStack stack, IMagicEffect effect) { + protected static EntitySpell castContainedSpell(World world, BlockPos pos, ItemStack stack, IMagicEffect effect) { EntitySpell spell = new EntitySpell(world); + spell.setEffect(effect); - spell.setLocationAndAngles(x + 0.5, y + 0.5, z + 0.5, 0, 0); + spell.setLocationAndAngles(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 0, 0); world.spawnEntity(spell); + return spell; - } */ + } } diff --git a/src/main/java/com/minelittlepony/unicopia/model/ModelGem.java b/src/main/java/com/minelittlepony/unicopia/model/ModelGem.java new file mode 100644 index 00000000..3b8ea7e9 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/model/ModelGem.java @@ -0,0 +1,126 @@ +package com.minelittlepony.unicopia.model; + +import com.minelittlepony.render.model.ModelQuads; +import com.minelittlepony.unicopia.entity.EntitySpell; +import com.minelittlepony.unicopia.spell.SpellRegistry; +import com.minelittlepony.util.render.Color; +import com.minelittlepony.util.render.Vertex; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.MathHelper; + +public class ModelGem extends ModelBase { + + private ModelRenderer body; + + public ModelGem() { + textureWidth = 256; + textureHeight = 256; + + body = new ModelRenderer(this); + body.offsetY = 1.2f; + + int size = 1; + + body.cubeList.add(new ModelQuads(body).addFace( + new Vertex( size, 0, size, 0, 0.5f), + new Vertex(-size, 0, size, 0.25f, 0.25f), + new Vertex( 0, size * 2, 0, 0, 0.25f), + new Vertex( 0, size * 2, 0, 0, 0.25f) + ).addFace( + new Vertex( size, 0, size, 0, 0.25f), + new Vertex(-size, 0, size, 0.25f, 0), + new Vertex( 0, -size * 2, 0, 0.25f, 0.25f), + new Vertex( 0, -size * 2, 0, 0.25f, 0.25f) + ).addFace( + new Vertex(size, 0, -size, 0.25f, 0.5f), + new Vertex(size, 0, size, 0.5f, 0.25f), + new Vertex(0, size * 2, 0, 0.25f, 0.25f), + new Vertex(0, size * 2, 0, 0.25f, 0.25f) + ).addFace( + new Vertex(size, 0, -size, 0.25f, 0.25f), + new Vertex(size, 0, size, 0.5f, 0), + new Vertex(0, -size * 2, 0, 0.5f, 0.25f), + new Vertex(0, -size * 2, 0, 0.5f, 0.25f) + ).addFace( + new Vertex(-size, 0, -size, 0.5f, 0.5f), + new Vertex( size, 0, -size, 0.75f, 0.25f), + new Vertex( 0, size * 2, 0, 0.5f, 0.25f), + new Vertex( 0, size * 2, 0, 0.5f, 0.25f) + ).addFace( + new Vertex(-size, 0, -size, 0.5f, 0.25f), + new Vertex( size, 0, -size, 0.75f, 0), + new Vertex( 0, -size * 2, 0, 0.75f, 0.25f), + new Vertex( 0, -size * 2, 0, 0.75f, 0.25f) + ).addFace( + new Vertex(-size, 0, size, 0.75f, 0.5f), + new Vertex(-size, 0, -size, 1, 0.25f), + new Vertex( 0, size * 2, 0, 0.75f, 0.25f), + new Vertex( 0, size * 2, 0, 0.75f, 0.25f) + ).addFace( + new Vertex(-size, 0, size, 0.75f, 0.25f), + new Vertex(-size, 0, -size, 1, 0), + new Vertex( 0, -size * 2, 0, 1, 0.25f), + new Vertex( 0, -size * 2, 0, 1, 0.25f) + )); + } + + @Override + public void render(Entity entity, float time, float walkSpeed, float stutter, float yaw, float pitch, float scale) { + + GlStateManager.pushMatrix(); + + EntitySpell spell = (EntitySpell)entity; + + float floatOffset = MathHelper.sin((spell.ticksExisted + stutter) / 10 + spell.hoverStart) / 10 + 0.1F; + GlStateManager.translate(0, floatOffset, 0); + + floatOffset = (spell.ticksExisted + stutter) / 20; + if (spell.getLevel() > 0) { + floatOffset *= spell.getLevel() + 1; + } + + floatOffset += spell.hoverStart; + floatOffset *= 180 / (float)Math.PI; + + GlStateManager.rotate(floatOffset, 0, 1, 0); + + body.render(scale); + + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.blendFunc(1, 1); + + setLightingConditionsBrightness(0xF0F0); + + Color.glColor(SpellRegistry.instance().getSpellTint(spell.getEffect().getName()), 1); + + GlStateManager.scale(1.2F, 1.2F, 1.2F); + GlStateManager.translate(0, -0.2F, 0); + + body.render(scale); + + setLightingConditionsBrightness(entity.getBrightnessForRender()); + + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + + GlStateManager.popMatrix(); + } + + private void setLightingConditionsBrightness(int brightness) { + int texX = brightness % 0x10000; + int texY = brightness / 0x10000; + + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, texX, texY); + } + + @Override + public void setRotationAngles(float time, float walkSpeed, float stutter, float yaw, float pitch, float increment, Entity entity) { + + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/EffectSync.java b/src/main/java/com/minelittlepony/unicopia/network/EffectSync.java new file mode 100644 index 00000000..e0cb5138 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/network/EffectSync.java @@ -0,0 +1,53 @@ +package com.minelittlepony.unicopia.network; + +import com.minelittlepony.unicopia.spell.ICaster; +import com.minelittlepony.unicopia.spell.IMagicEffect; +import com.minelittlepony.unicopia.spell.SpellRegistry; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.datasync.DataParameter; + +public class EffectSync { + private IMagicEffect effect; + + private final ICaster owned; + + private final DataParameter param; + + public EffectSync(ICaster owned, DataParameter param) { + this.owned = owned; + this.param = param; + } + + public boolean has() { + return get() != null; + } + + public IMagicEffect get() { + NBTTagCompound comp = owned.getEntity().getDataManager().get(param); + + if (comp == null || !comp.hasKey("effect_id")) { + effect = null; + } else { + String id = comp.getString("effect_id"); + if (effect == null || id != effect.getName()) { + effect = SpellRegistry.instance().createEffectFromNBT(comp); + } else { + effect.readFromNBT(comp); + } + } + + return effect; + } + + public void set(IMagicEffect effect) { + this.effect = effect; + + if (effect == null) { + owned.getEntity().getDataManager().set(param, new NBTTagCompound()); + } else { + owned.getEntity().getDataManager().set(param, SpellRegistry.instance().serializeEffectToNBT(effect)); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerAbility.java b/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerAbility.java index 78a51a66..261933f1 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerAbility.java @@ -32,13 +32,13 @@ public class MsgPlayerAbility implements IMessage, IMessageHandler power, IData data) { - senderId = player.getGameProfile().getId(); + senderId = player.getUniqueID(); powerIdentifier = power.getKeyName(); abilityJson = gson.toJson(data, power.getPackageType()); } private void apply(IPower power) { - EntityPlayer player = IPlayer.getPlayerEntity(senderId); + EntityPlayer player = IPlayer.getPlayerFromServer(senderId); if (player == null) { return; } diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java b/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java index 2f1b0b9d..3173e6f5 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java +++ b/src/main/java/com/minelittlepony/unicopia/network/MsgPlayerCapabilities.java @@ -15,7 +15,6 @@ import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.player.IPlayer; import com.minelittlepony.unicopia.player.PlayerSpeciesList; -import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; @@ -32,12 +31,14 @@ public class MsgPlayerCapabilities implements IMessage, IMessageHandler 0) { + try (ByteArrayInputStream input = new ByteArrayInputStream(compoundTag)) { + NBTTagCompound nbt = CompressedStreamTools.read(new DataInputStream(input)); + + player.readFromNBT(nbt); + } catch (IOException e) { + + } + } else { + player.setPlayerSpecies(newRace); } - - player = PlayerSpeciesList.instance().getPlayer(found); - } - - if (compoundTag.length > 0) { - try (ByteArrayInputStream input = new ByteArrayInputStream(compoundTag)) { - NBTTagCompound nbt = CompressedStreamTools.read(new DataInputStream(input)); - - player.readFromNBT(nbt); - } catch (IOException e) { - } - } else { - player.setPlayerSpecies(newRace); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/MsgRequestCapabilities.java b/src/main/java/com/minelittlepony/unicopia/network/MsgRequestCapabilities.java index 38b5c689..3ce8e574 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/MsgRequestCapabilities.java +++ b/src/main/java/com/minelittlepony/unicopia/network/MsgRequestCapabilities.java @@ -25,6 +25,6 @@ public class MsgRequestCapabilities implements IMessage, IMessageHandler, IRaceContainer { - private static final Logger logger = LogManager.getLogger(); - private static final DataParameter PLAYER_RACE = EntityDataManager .createKey(EntityPlayer.class, DataSerializers.VARINT); + private static final DataParameter EXERTION = EntityDataManager .createKey(EntityPlayer.class, DataSerializers.FLOAT); + private static final DataParameter EFFECT = EntityDataManager + .createKey(EntityPlayer.class, DataSerializers.COMPOUND_TAG); + private final PlayerAbilityDelegate powers = new PlayerAbilityDelegate(this); private final PlayerGravityDelegate gravity = new PlayerGravityDelegate(this); private final PlayerAttributes attributes = new PlayerAttributes(); + private final EffectSync effectDelegate = new EffectSync<>(this, EFFECT); + private float nextStepDistance = 1; - private IMagicEffect effect; - private EntityPlayer entity; - private UUID playerId; PlayerCapabilities(EntityPlayer player) { setOwner(player); player.getDataManager().register(PLAYER_RACE, Race.HUMAN.ordinal()); player.getDataManager().register(EXERTION, 0F); + player.getDataManager().register(EFFECT, new NBTTagCompound()); } @Override @@ -66,21 +64,19 @@ class PlayerCapabilities implements IPlayer, ICaster { @Override public void setPlayerSpecies(Race race) { - EntityPlayer self = getOwner(); + EntityPlayer player = getOwner(); - if (!PlayerSpeciesList.instance().speciesPermitted(race, getOwner())) { + if (!PlayerSpeciesList.instance().speciesPermitted(race, player)) { race = Race.HUMAN; } - if (self != null) { - getOwner().getDataManager().set(PLAYER_RACE, race.ordinal()); + player.getDataManager().set(PLAYER_RACE, race.ordinal()); - self.capabilities.allowFlying = race.canFly(); - gravity.updateFlightStat(self, self.capabilities.isFlying); + player.capabilities.allowFlying = race.canFly(); + gravity.updateFlightStat(player, player.capabilities.isFlying); - self.sendPlayerAbilities(); - sendCapabilities(false); - } + player.sendPlayerAbilities(); + sendCapabilities(false); } @Override @@ -96,10 +92,12 @@ class PlayerCapabilities implements IPlayer, ICaster { @Override public void sendCapabilities(boolean full) { if (!getOwner().getEntityWorld().isRemote) { + System.out.println("[SERVER] Sending player capabilities."); + if (full) { Unicopia.channel.broadcast(new MsgPlayerCapabilities(this)); } else { - Unicopia.channel.broadcast(new MsgPlayerCapabilities(getPlayerSpecies(), getOwner().getGameProfile().getId())); + Unicopia.channel.broadcast(new MsgPlayerCapabilities(getPlayerSpecies(), getOwner())); } } } @@ -136,15 +134,15 @@ class PlayerCapabilities implements IPlayer, ICaster { powers.onUpdate(entity); gravity.onUpdate(entity); - if (effect != null) { + if (hasEffect()) { if (!getPlayerSpecies().canCast()) { setEffect(null); } else { if (entity.getEntityWorld().isRemote) { // && entity.getEntityWorld().getWorldTime() % 10 == 0 - effect.render(entity); + getEffect().render(entity); } - if (!effect.update(entity)) { + if (!getEffect().update(entity)) { setEffect(null); } } @@ -196,21 +194,27 @@ class PlayerCapabilities implements IPlayer, ICaster { @Override public void writeToNBT(NBTTagCompound compound) { compound.setString("playerSpecies", getPlayerSpecies().name()); + compound.setTag("powers", powers.toNBT()); compound.setTag("gravity", gravity.toNBT()); + IMagicEffect effect = getEffect(); + if (effect != null) { - compound.setString("effect_id", effect.getName()); - compound.setTag("effect", effect.toNBT()); + compound.setTag("effect", SpellRegistry.instance().serializeEffectToNBT(effect)); } } @Override public void readFromNBT(NBTTagCompound compound) { setPlayerSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN)); + powers.readFromNBT(compound.getCompoundTag("powers")); gravity.readFromNBT(compound.getCompoundTag("gravity")); - effect = SpellRegistry.instance().createEffectFroNBT(compound); + + if (compound.hasKey("effect")) { + setEffect(SpellRegistry.instance().createEffectFromNBT(compound.getCompoundTag("effect"))); + } } @Override @@ -221,30 +225,23 @@ class PlayerCapabilities implements IPlayer, ICaster { @Override public void setEffect(IMagicEffect effect) { - this.effect = effect; + effectDelegate.set(effect); sendCapabilities(true); } @Override public IMagicEffect getEffect() { - return effect; + return effectDelegate.get(); } @Override public void setOwner(EntityPlayer owner) { entity = owner; - playerId = owner.getGameProfile().getId(); } @Override public EntityPlayer getOwner() { - if (entity == null) { - entity = IPlayer.getPlayerEntity(playerId); - if (entity == null) { - logger.error("Capabilities without player! Mismatched id was" + playerId); - } - } return entity; } } diff --git a/src/main/java/com/minelittlepony/unicopia/player/PlayerSpeciesList.java b/src/main/java/com/minelittlepony/unicopia/player/PlayerSpeciesList.java index 9210c2c0..d0b63e7a 100644 --- a/src/main/java/com/minelittlepony/unicopia/player/PlayerSpeciesList.java +++ b/src/main/java/com/minelittlepony/unicopia/player/PlayerSpeciesList.java @@ -46,7 +46,7 @@ public class PlayerSpeciesList { } public IPlayer getPlayer(UUID playerId) { - return getPlayer(IPlayer.getPlayerEntity(playerId)); + return getPlayer(IPlayer.getPlayerFromServer(playerId)); } public IRaceContainer getEntity(T entity) { diff --git a/src/main/java/com/minelittlepony/unicopia/render/RenderGem.java b/src/main/java/com/minelittlepony/unicopia/render/RenderGem.java new file mode 100644 index 00000000..8ac70871 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/render/RenderGem.java @@ -0,0 +1,30 @@ +package com.minelittlepony.unicopia.render; + +import com.minelittlepony.unicopia.entity.EntitySpell; +import com.minelittlepony.unicopia.model.ModelGem; + +import net.minecraft.client.renderer.entity.RenderLiving; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.util.ResourceLocation; + +public class RenderGem extends RenderLiving { + + private static final ResourceLocation gem = new ResourceLocation("unicopia", "textures/entity/gem.png"); + + public RenderGem(RenderManager rendermanagerIn) { + super(rendermanagerIn, new ModelGem(), 0); + } + + protected ResourceLocation getEntityTexture(EntitySpell entity) { + return gem; + } + + protected float getDeathMaxRotation(EntitySpell entity) { + return 0; + } + + protected boolean canRenderName(EntitySpell targetEntity) { + return super.canRenderName(targetEntity) && (targetEntity.getAlwaysRenderNameTagForRender() + || targetEntity.hasCustomName() && targetEntity == renderManager.pointedEntity); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java b/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java index 1226edbe..fbbb5e90 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/ICaster.java @@ -14,6 +14,9 @@ public interface ICaster extends IOwned { return getEffect() != null; } + /** + * Gets the entity directly responsible for casting. + */ default Entity getEntity() { return getOwner(); } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/IDispenceable.java b/src/main/java/com/minelittlepony/unicopia/spell/IDispenceable.java index 9e235f77..ef9f8415 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/IDispenceable.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/IDispenceable.java @@ -6,13 +6,13 @@ import net.minecraft.util.EnumFacing; /** * Represents an object with an action to perform when dispensed from a dispenser. - * + * */ -public interface IDispenceable { - +public interface IDispenceable extends IMagicEffect { + /** * Called when dispensed. - * + * * @param pos Block position in front of the dispenser * @param facing Direction of the dispenser * @param source The dispenser currently dispensing diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellRegistry.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellRegistry.java index 4c84f6f8..57ab22ce 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellRegistry.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellRegistry.java @@ -34,8 +34,8 @@ public class SpellRegistry { return null; } - public IMagicEffect createEffectFroNBT(NBTTagCompound compound) { - if (compound.hasKey("effect_id") && compound.hasKey("effect")) { + public IMagicEffect createEffectFromNBT(NBTTagCompound compound) { + if (compound.hasKey("effect_id")) { IMagicEffect effect = getSpellFromName(compound.getString("effect_id")); if (effect != null) { @@ -48,6 +48,14 @@ public class SpellRegistry { return null; } + public NBTTagCompound serializeEffectToNBT(IMagicEffect effect) { + NBTTagCompound compound = effect.toNBT(); + + compound.setString("effect_id", effect.getName()); + + return compound; + } + public IDispenceable getDispenseActionFrom(ItemStack stack) { String key = getKeyFromStack(stack); @@ -80,7 +88,7 @@ public class SpellRegistry { return stack; } - private String getKeyFromStack(ItemStack stack) { + public static String getKeyFromStack(ItemStack stack) { if (stack.isEmpty() || !stack.hasTagCompound() || !stack.getTagCompound().hasKey("spell")) { return ""; } diff --git a/src/main/java/com/minelittlepony/unicopia/spell/SpellShield.java b/src/main/java/com/minelittlepony/unicopia/spell/SpellShield.java index 972a12eb..2eb6b473 100644 --- a/src/main/java/com/minelittlepony/unicopia/spell/SpellShield.java +++ b/src/main/java/com/minelittlepony/unicopia/spell/SpellShield.java @@ -57,7 +57,7 @@ public class SpellShield extends AbstractSpell { protected void spawnParticles(World w, double x, double y, double z, int strength) { IShape sphere = new Sphere(true, strength); - for (int i = 0; i < strength; i++) { + for (int i = 0; i < strength * 6; i++) { Vec3d pos = sphere.computePoint(w.rand); Particles.instance().spawnParticle(Unicopia.MAGIC_PARTICLE, false, pos.x + x, pos.y + y, pos.z + z, diff --git a/src/main/resources/assets/unicopia/textures/entity/gem.png b/src/main/resources/assets/unicopia/textures/entity/gem.png new file mode 100644 index 00000000..86b1b195 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/entity/gem.png differ