mirror of
https://github.com/FalsePattern/FalsePatternLib.git
synced 2026-11-15 18:24:45 +00:00
reformat code
This commit is contained in:
21 files changed
+731
-498
No files matched your search
@@ -7,13 +7,13 @@ import java.lang.annotation.RetentionPolicy;
|
||||
/**
|
||||
* Anything annotated with this annotation will be considered stable, and the class/method/field will not get breaking
|
||||
* changes without a full deprecation cycle.
|
||||
*
|
||||
* If a class or method is NOT annotated with this annotation, it will be considered unstable, and the package/method arguments/etc.
|
||||
* can freely change between patch releases without notice.
|
||||
*
|
||||
* <p>
|
||||
* If a class or method is NOT annotated with this annotation, it will be considered unstable, and the package/method
|
||||
* arguments/etc. can freely change between patch releases without notice.
|
||||
* <p>
|
||||
* If a class is annotated with this annotation, all currently existing public and protected members in the class will
|
||||
* be considered stable.
|
||||
*
|
||||
* <p>
|
||||
* Private members will never be considered stable, and can be removed without notice.
|
||||
*/
|
||||
@Documented
|
||||
|
||||
@@ -4,7 +4,13 @@ import com.falsepattern.lib.StableAPI;
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import lombok.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
import lombok.val;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.MathHelper;
|
||||
@@ -12,11 +18,12 @@ import net.minecraft.util.Vec3;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.minecraft.util.EnumFacing.*;
|
||||
import static net.minecraft.util.EnumFacing.DOWN;
|
||||
import static net.minecraft.util.EnumFacing.EAST;
|
||||
import static net.minecraft.util.EnumFacing.NORTH;
|
||||
import static net.minecraft.util.EnumFacing.SOUTH;
|
||||
import static net.minecraft.util.EnumFacing.UP;
|
||||
import static net.minecraft.util.EnumFacing.WEST;
|
||||
|
||||
@Immutable
|
||||
@StableAPI(since = "0.6.0")
|
||||
@@ -35,18 +42,14 @@ public class BlockPos extends Vec3i {
|
||||
private static final long Z_MASK = (1L << NUM_Z_BITS) - 1L;
|
||||
private static final long X_MASK = (1L << NUM_X_BITS) - 1L;
|
||||
|
||||
public BlockPos(int x, int y, int z) {
|
||||
super(x, y, z);
|
||||
public BlockPos(@NonNull Entity source) {
|
||||
this(source.posX, source.posY, source.posZ);
|
||||
}
|
||||
|
||||
public BlockPos(double x, double y, double z) {
|
||||
super(x, y, z);
|
||||
}
|
||||
|
||||
public BlockPos(@NonNull Entity source) {
|
||||
this(source.posX, source.posY, source.posZ);
|
||||
}
|
||||
|
||||
public BlockPos(@NonNull Vec3 vec) {
|
||||
this(vec.xCoord, vec.yCoord, vec.zCoord);
|
||||
}
|
||||
@@ -55,46 +58,47 @@ public class BlockPos extends Vec3i {
|
||||
this(source.getX(), source.getY(), source.getZ());
|
||||
}
|
||||
|
||||
public BlockPos(int x, int y, int z) {
|
||||
super(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a BlockPos from a serialized long value (created by toLong)
|
||||
*/
|
||||
public static BlockPos fromLong(long serialized) {
|
||||
return new BlockPos(
|
||||
(int) (serialized << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS),
|
||||
(int) (serialized << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS),
|
||||
(int) (serialized << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS)
|
||||
);
|
||||
}
|
||||
|
||||
public long toLong() {
|
||||
return ((long) x & X_MASK) << X_SHIFT | ((long) y & Y_MASK) << Y_SHIFT | ((long) z & Z_MASK);
|
||||
return new BlockPos((int) (serialized << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS),
|
||||
(int) (serialized << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS),
|
||||
(int) (serialized << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Iterable that returns all positions in the box specified by the given corners. There is no requirement
|
||||
* that one corner is greater than the other; individual coordinates will be swapped as needed.
|
||||
* <p>
|
||||
* In situations where it is usable, prefer {@link #getAllInBoxMutable(BlockPos, BlockPos) instead as it has better
|
||||
* performance (fewer allocations)
|
||||
* In situations where it is usable, prefer
|
||||
* {@link #getAllInBoxMutable(BlockPos, BlockPos) instead as it has better performance (fewer allocations)
|
||||
*
|
||||
* @param from One corner of the box
|
||||
* @param to Another corner of the box
|
||||
*
|
||||
* @see #getAllInBox(int, int, int, int, int, int)
|
||||
* @see #getAllInBoxMutable(BlockPos, BlockPos)
|
||||
*/
|
||||
public static Iterable<BlockPos> getAllInBox(@NonNull BlockPos from, @NonNull BlockPos to) {
|
||||
return getAllInBox(
|
||||
Math.min(from.getX(), to.getX()), Math.min(from.getY(), to.getY()), Math.min(from.getZ(), to.getZ()),
|
||||
Math.max(from.getX(), to.getX()), Math.max(from.getY(), to.getY()), Math.max(from.getZ(), to.getZ())
|
||||
);
|
||||
return getAllInBox(Math.min(from.getX(), to.getX()),
|
||||
Math.min(from.getY(), to.getY()),
|
||||
Math.min(from.getZ(), to.getZ()),
|
||||
Math.max(from.getX(), to.getX()),
|
||||
Math.max(from.getY(), to.getY()),
|
||||
Math.max(from.getZ(), to.getZ()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Iterable that returns all positions in the box specified by the coordinates. <strong>Coordinates must
|
||||
* be in order</strong>; e.g. x0 <= x1.
|
||||
* <p>
|
||||
* In situations where it is usable, prefer {@link #getAllInBoxMutable(BlockPos, BlockPos) instead as it has better
|
||||
* performance (fewer allocations)
|
||||
* In situations where it is usable, prefer
|
||||
* {@link #getAllInBoxMutable(BlockPos, BlockPos) instead as it has better performance (fewer allocations)
|
||||
*
|
||||
* @param x0 The lower x coordinate
|
||||
* @param y0 The lower y coordinate
|
||||
@@ -102,11 +106,16 @@ public class BlockPos extends Vec3i {
|
||||
* @param x1 The upper x coordinate
|
||||
* @param y1 The upper y coordinate
|
||||
* @param z1 The upper z coordinate
|
||||
*
|
||||
* @see #getAllInBox(BlockPos, BlockPos)
|
||||
* @see #getAllInBoxMutable(BlockPos, BlockPos)
|
||||
*/
|
||||
public static Iterable<BlockPos> getAllInBox(final int x0, final int y0, final int z0,
|
||||
final int x1, final int y1, final int z1) {
|
||||
public static Iterable<BlockPos> getAllInBox(final int x0,
|
||||
final int y0,
|
||||
final int z0,
|
||||
final int x1,
|
||||
final int y1,
|
||||
final int z1) {
|
||||
return () -> new AbstractIterator<BlockPos>() {
|
||||
private boolean first = true;
|
||||
private int lastX;
|
||||
@@ -122,8 +131,9 @@ public class BlockPos extends Vec3i {
|
||||
lastZ = z0;
|
||||
return new BlockPos(x0, y0, z0);
|
||||
}
|
||||
if (lastX == x1 && lastY == y1 && lastZ == z1)
|
||||
if (lastX == x1 && lastY == y1 && lastZ == z1) {
|
||||
return endOfData();
|
||||
}
|
||||
if (lastX < x1) {
|
||||
lastX++;
|
||||
} else if (lastY < y1) {
|
||||
@@ -150,14 +160,18 @@ public class BlockPos extends Vec3i {
|
||||
*
|
||||
* @param from One corner of the box
|
||||
* @param to Another corner of the box
|
||||
*
|
||||
* @see #getAllInBox(BlockPos, BlockPos)
|
||||
* @see #getAllInBox(int, int, int, int, int, int)
|
||||
* @see #getAllInBoxMutable(BlockPos, BlockPos)
|
||||
*/
|
||||
public static Iterable<BlockPos.MutableBlockPos> getAllInBoxMutable(@NonNull BlockPos from, @NonNull BlockPos to) {
|
||||
return getAllInBoxMutable(
|
||||
Math.min(from.getX(), to.getX()), Math.min(from.getY(), to.getY()), Math.min(from.getZ(), to.getZ()),
|
||||
Math.max(from.getX(), to.getX()), Math.max(from.getY(), to.getY()), Math.max(from.getZ(), to.getZ()));
|
||||
return getAllInBoxMutable(Math.min(from.getX(), to.getX()),
|
||||
Math.min(from.getY(), to.getY()),
|
||||
Math.min(from.getZ(), to.getZ()),
|
||||
Math.max(from.getX(), to.getX()),
|
||||
Math.max(from.getY(), to.getY()),
|
||||
Math.max(from.getZ(), to.getZ()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,12 +189,17 @@ public class BlockPos extends Vec3i {
|
||||
* @param x1 The upper x coordinate
|
||||
* @param y1 The upper y coordinate
|
||||
* @param z1 The upper z coordinate
|
||||
*
|
||||
* @see #getAllInBox(BlockPos, BlockPos)
|
||||
* @see #getAllInBox(int, int, int, int, int, int)
|
||||
* @see #getAllInBoxMutable(BlockPos, BlockPos)
|
||||
*/
|
||||
public static Iterable<BlockPos.MutableBlockPos> getAllInBoxMutable(final int x0, final int y0, final int z0,
|
||||
final int x1, final int y1, final int z1) {
|
||||
public static Iterable<BlockPos.MutableBlockPos> getAllInBoxMutable(final int x0,
|
||||
final int y0,
|
||||
final int z0,
|
||||
final int x1,
|
||||
final int y1,
|
||||
final int z1) {
|
||||
return () -> new AbstractIterator<MutableBlockPos>() {
|
||||
private MutableBlockPos pos;
|
||||
|
||||
@@ -208,21 +227,17 @@ public class BlockPos extends Vec3i {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given coordinates to the coordinates of this BlockPos
|
||||
*/
|
||||
public BlockPos add(double x, double y, double z) {
|
||||
if (x == 0.0D && y == 0.0D && z == 0.0D)
|
||||
return this;
|
||||
return new BlockPos(this.x + x, this.y + y, this.z + z);
|
||||
public long toLong() {
|
||||
return ((long) x & X_MASK) << X_SHIFT | ((long) y & Y_MASK) << Y_SHIFT | ((long) z & Z_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given coordinates to the coordinates of this BlockPos
|
||||
*/
|
||||
public BlockPos add(int x, int y, int z) {
|
||||
if (x == 0 && y == 0 && z == 0)
|
||||
public BlockPos add(double x, double y, double z) {
|
||||
if (x == 0.0D && y == 0.0D && z == 0.0D) {
|
||||
return this;
|
||||
}
|
||||
return new BlockPos(this.x + x, this.y + y, this.z + z);
|
||||
}
|
||||
|
||||
@@ -233,6 +248,16 @@ public class BlockPos extends Vec3i {
|
||||
return add(vec.getX(), vec.getY(), vec.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given coordinates to the coordinates of this BlockPos
|
||||
*/
|
||||
public BlockPos add(int x, int y, int z) {
|
||||
if (x == 0 && y == 0 && z == 0) {
|
||||
return this;
|
||||
}
|
||||
return new BlockPos(this.x + x, this.y + y, this.z + z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract the given Vector from this BlockPos
|
||||
*/
|
||||
@@ -248,6 +273,15 @@ public class BlockPos extends Vec3i {
|
||||
return offset(UP, blocks);
|
||||
}
|
||||
|
||||
public BlockPos offset(@NonNull EnumFacing facing, int blocks) {
|
||||
if (blocks == 0) {
|
||||
return this;
|
||||
}
|
||||
return new BlockPos(x + facing.getFrontOffsetX() * blocks,
|
||||
y + facing.getFrontOffsetY() * blocks,
|
||||
z + facing.getFrontOffsetZ() * blocks);
|
||||
}
|
||||
|
||||
public BlockPos down() {
|
||||
return down(1);
|
||||
}
|
||||
@@ -292,16 +326,6 @@ public class BlockPos extends Vec3i {
|
||||
return offset(facing, 1);
|
||||
}
|
||||
|
||||
public BlockPos offset(@NonNull EnumFacing facing, int blocks) {
|
||||
if (blocks == 0)
|
||||
return this;
|
||||
return new BlockPos(
|
||||
x + facing.getFrontOffsetX() * blocks,
|
||||
y + facing.getFrontOffsetY() * blocks,
|
||||
z + facing.getFrontOffsetZ() * blocks
|
||||
);
|
||||
}
|
||||
|
||||
public BlockPos rotate(@NonNull Rotation rotation) {
|
||||
switch (rotation) {
|
||||
case NONE:
|
||||
@@ -318,11 +342,9 @@ public class BlockPos extends Vec3i {
|
||||
|
||||
@Override
|
||||
public BlockPos crossProduct(@NonNull Vec3i vec) {
|
||||
return new BlockPos(
|
||||
y * vec.getZ() - z * vec.getY(),
|
||||
z * vec.getX() - x * vec.getZ(),
|
||||
x * vec.getY() - y * vec.getX()
|
||||
);
|
||||
return new BlockPos(y * vec.getZ() - z * vec.getY(),
|
||||
z * vec.getX() - x * vec.getZ(),
|
||||
x * vec.getY() - y * vec.getX());
|
||||
}
|
||||
|
||||
public BlockPos toImmutable() {
|
||||
@@ -380,12 +402,17 @@ public class BlockPos extends Vec3i {
|
||||
return super.rotate(rotation).toImmutable();
|
||||
}
|
||||
|
||||
public BlockPos toImmutable() {
|
||||
return new BlockPos(this);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public BlockPos.MutableBlockPos setPos(@NonNull Entity entity) {
|
||||
return this.setPos(entity.posX, entity.posY, entity.posZ);
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos setPos(double x, double y, double z) {
|
||||
return setPos(
|
||||
MathHelper.floor_double(x),
|
||||
MathHelper.floor_double(y),
|
||||
MathHelper.floor_double(z)
|
||||
);
|
||||
return setPos(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z));
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos setPos(int x, int y, int z) {
|
||||
@@ -395,11 +422,6 @@ public class BlockPos extends Vec3i {
|
||||
return this;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public BlockPos.MutableBlockPos setPos(@NonNull Entity entity) {
|
||||
return this.setPos(entity.posX, entity.posY, entity.posZ);
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos setPos(@NonNull Vec3i vec) {
|
||||
return this.setPos(vec.getX(), vec.getY(), vec.getZ());
|
||||
}
|
||||
@@ -409,15 +431,9 @@ public class BlockPos extends Vec3i {
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos move(@NonNull EnumFacing facing, int blocks) {
|
||||
return this.setPos(
|
||||
x + facing.getFrontOffsetX() * blocks,
|
||||
y + facing.getFrontOffsetY() * blocks,
|
||||
z + facing.getFrontOffsetZ() * blocks
|
||||
);
|
||||
}
|
||||
|
||||
public BlockPos toImmutable() {
|
||||
return new BlockPos(this);
|
||||
return this.setPos(x + facing.getFrontOffsetX() * blocks,
|
||||
y + facing.getFrontOffsetY() * blocks,
|
||||
z + facing.getFrontOffsetZ() * blocks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,15 +449,6 @@ public class BlockPos extends Vec3i {
|
||||
return retain(0, 0, 0);
|
||||
}
|
||||
|
||||
public static BlockPos.PooledMutableBlockPos retain(double x, double y, double z) {
|
||||
return retain(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z));
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static BlockPos.PooledMutableBlockPos retain(@NonNull Vec3i vec) {
|
||||
return retain(vec.getX(), vec.getY(), vec.getZ());
|
||||
}
|
||||
|
||||
public static BlockPos.PooledMutableBlockPos retain(int x, int y, int z) {
|
||||
synchronized (POOL) {
|
||||
if (!POOL.isEmpty()) {
|
||||
@@ -456,6 +463,15 @@ public class BlockPos extends Vec3i {
|
||||
return new BlockPos.PooledMutableBlockPos(x, y, z);
|
||||
}
|
||||
|
||||
public static BlockPos.PooledMutableBlockPos retain(double x, double y, double z) {
|
||||
return retain(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z));
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static BlockPos.PooledMutableBlockPos retain(@NonNull Vec3i vec) {
|
||||
return retain(vec.getX(), vec.getY(), vec.getZ());
|
||||
}
|
||||
|
||||
public void release() {
|
||||
synchronized (POOL) {
|
||||
if (POOL.size() < 100) {
|
||||
@@ -465,15 +481,6 @@ public class BlockPos extends Vec3i {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos.PooledMutableBlockPos setPos(int x, int y, int z) {
|
||||
if (released) {
|
||||
BlockPos.LOGGER.error("PooledMutableBlockPosition modified after it was released.", new Throwable());
|
||||
released = false;
|
||||
}
|
||||
return (BlockPos.PooledMutableBlockPos) super.setPos(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public BlockPos.PooledMutableBlockPos setPos(@NonNull Entity entity) {
|
||||
@@ -485,6 +492,15 @@ public class BlockPos extends Vec3i {
|
||||
return (BlockPos.PooledMutableBlockPos) super.setPos(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos.PooledMutableBlockPos setPos(int x, int y, int z) {
|
||||
if (released) {
|
||||
BlockPos.LOGGER.error("PooledMutableBlockPosition modified after it was released.", new Throwable());
|
||||
released = false;
|
||||
}
|
||||
return (BlockPos.PooledMutableBlockPos) super.setPos(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos.PooledMutableBlockPos setPos(@NonNull Vec3i vec) {
|
||||
return (BlockPos.PooledMutableBlockPos) super.setPos(vec);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package com.falsepattern.lib.compat;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import lombok.*;
|
||||
import net.minecraft.entity.Entity;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
import net.minecraft.entity.Entity;
|
||||
|
||||
/**
|
||||
* A functional equivalent to ChunkPos present in Minecraft 1.12.
|
||||
@@ -38,6 +40,7 @@ public class ChunkPos {
|
||||
*
|
||||
* @param x the chunk x
|
||||
* @param z the chunk x
|
||||
*
|
||||
* @return the unique chunk long
|
||||
*/
|
||||
public static long asLong(int x, int z) {
|
||||
@@ -48,6 +51,7 @@ public class ChunkPos {
|
||||
* Gets distance sq.
|
||||
*
|
||||
* @param entity the entity
|
||||
*
|
||||
* @return the distance sq
|
||||
*/
|
||||
public double getDistanceSq(@NonNull Entity entity) {
|
||||
@@ -98,6 +102,7 @@ public class ChunkPos {
|
||||
* @param x the x pos
|
||||
* @param y the y pos
|
||||
* @param z the z pos
|
||||
*
|
||||
* @return the relative block position
|
||||
*/
|
||||
public BlockPos getBlock(int x, int y, int z) {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package com.falsepattern.lib.compat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import lombok.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
import lombok.var;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
@@ -21,16 +22,6 @@ public class GuiLabel extends Gui {
|
||||
private final List<String> lines = new ArrayList<>();
|
||||
private final FontRenderer fontRenderer;
|
||||
private final int textColor;
|
||||
|
||||
private boolean centered = false;
|
||||
/**
|
||||
* The label width.
|
||||
*/
|
||||
protected int width;
|
||||
/**
|
||||
* The label height.
|
||||
*/
|
||||
protected int height;
|
||||
/**
|
||||
* The id of the label.
|
||||
*/
|
||||
@@ -47,6 +38,15 @@ public class GuiLabel extends Gui {
|
||||
* The visibility of the label.
|
||||
*/
|
||||
public boolean visible = true;
|
||||
/**
|
||||
* The label width.
|
||||
*/
|
||||
protected int width;
|
||||
/**
|
||||
* The label height.
|
||||
*/
|
||||
protected int height;
|
||||
private boolean centered = false;
|
||||
|
||||
/**
|
||||
* Instantiates a new Gui label.
|
||||
@@ -97,8 +97,9 @@ public class GuiLabel extends Gui {
|
||||
* @param mouseY the mouse y
|
||||
*/
|
||||
public void drawLabel(@NonNull Minecraft minecraft, int mouseX, int mouseY) {
|
||||
if (!visible)
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package com.falsepattern.lib.compat;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import lombok.*;
|
||||
import lombok.NonNull;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@StableAPI(since = "0.6.0")
|
||||
public enum Rotation {
|
||||
NONE, CLOCKWISE_90, CLOCKWISE_180, COUNTERCLOCKWISE_90;
|
||||
NONE,
|
||||
CLOCKWISE_90,
|
||||
CLOCKWISE_180,
|
||||
COUNTERCLOCKWISE_90;
|
||||
|
||||
public Rotation add(@NonNull Rotation rotation) {
|
||||
switch (rotation) {
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.falsepattern.lib.compat;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import lombok.*;
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
/**
|
||||
* A functional equivalent to Vec3i present in Minecraft 1.12.
|
||||
@@ -43,14 +46,13 @@ public class Vec3i implements Comparable<Vec3i> {
|
||||
* Cross product between two vectors.
|
||||
*
|
||||
* @param vec the other vector
|
||||
*
|
||||
* @return the new resulting vector
|
||||
*/
|
||||
public Vec3i crossProduct(@NonNull Vec3i vec) {
|
||||
return new Vec3i(
|
||||
y * vec.getZ() - z * vec.getY(),
|
||||
z * vec.getX() - x * vec.getZ(),
|
||||
x * vec.getY() - y * vec.getX()
|
||||
);
|
||||
return new Vec3i(y * vec.getZ() - z * vec.getY(),
|
||||
z * vec.getX() - x * vec.getZ(),
|
||||
x * vec.getY() - y * vec.getX());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,28 +61,20 @@ public class Vec3i implements Comparable<Vec3i> {
|
||||
* @param x the other x
|
||||
* @param y the other y
|
||||
* @param z the other z
|
||||
*
|
||||
* @return the distance
|
||||
*/
|
||||
public double getDistance(int x, int y, int z) {
|
||||
return Math.sqrt(distanceSq(x, y, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Square distance between vectors.
|
||||
*
|
||||
* @param vec the other vector
|
||||
* @return the square distance
|
||||
*/
|
||||
public double distanceSq(@NonNull Vec3i vec) {
|
||||
return distanceSq(vec.getX(), vec.getY(), vec.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Square root distance to a point.
|
||||
*
|
||||
* @param x the other x
|
||||
* @param y the other y
|
||||
* @param z the other z
|
||||
*
|
||||
* @return the square distance
|
||||
*/
|
||||
public double distanceSq(int x, int y, int z) {
|
||||
@@ -90,12 +84,24 @@ public class Vec3i implements Comparable<Vec3i> {
|
||||
return dX * dX + dY * dY + dZ * dZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Square distance between vectors.
|
||||
*
|
||||
* @param vec the other vector
|
||||
*
|
||||
* @return the square distance
|
||||
*/
|
||||
public double distanceSq(@NonNull Vec3i vec) {
|
||||
return distanceSq(vec.getX(), vec.getY(), vec.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Square distance between point to center of this Block.
|
||||
*
|
||||
* @param x the other x
|
||||
* @param y the other y
|
||||
* @param z the other z
|
||||
*
|
||||
* @return the square distance to center
|
||||
*/
|
||||
public double distanceSqToCenter(double x, double y, double z) {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.falsepattern.lib.config;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -33,7 +36,8 @@ public @interface Config {
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface Ignore {}
|
||||
@interface Ignore {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -95,9 +99,11 @@ public @interface Config {
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
@interface RequiresMcRestart {}
|
||||
@interface RequiresMcRestart {
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
@interface RequiresWorldRestart {}
|
||||
@interface RequiresWorldRestart {
|
||||
}
|
||||
}
|
||||
@@ -7,17 +7,25 @@ import cpw.mods.fml.client.config.IConfigElement;
|
||||
import cpw.mods.fml.client.event.ConfigChangedEvent;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import lombok.*;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.config.ConfigElement;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
import lombok.var;
|
||||
import net.minecraftforge.common.config.ConfigElement;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
|
||||
/**
|
||||
* Class for controlling the loading of configuration files.
|
||||
@@ -37,16 +45,17 @@ public class ConfigurationManager {
|
||||
|
||||
/**
|
||||
* Registers a configuration class to be loaded. This should be done in preInit.
|
||||
*
|
||||
* @param configClass The class to register.
|
||||
*/
|
||||
public static void registerConfig(Class<?> configClass) throws ConfigException {
|
||||
val cfg = Optional
|
||||
.ofNullable(configClass.getAnnotation(Config.class))
|
||||
.orElseThrow(() -> new ConfigException("Class " + configClass.getName() + " does not have a @Config annotation!"));
|
||||
val category = Optional
|
||||
.of(cfg.category().trim())
|
||||
.map((cat) -> cat.length() == 0 ? null : cat)
|
||||
.orElseThrow(() -> new ConfigException("Config class " + configClass.getName() + " has an empty category!"));
|
||||
val cfg = Optional.ofNullable(configClass.getAnnotation(Config.class))
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Class " + configClass.getName() + " does not have a @Config annotation!"));
|
||||
val category = Optional.of(cfg.category().trim())
|
||||
.map((cat) -> cat.length() == 0 ? null : cat)
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Config class " + configClass.getName() + " has an empty category!"));
|
||||
val rawConfig = configs.computeIfAbsent(cfg.modid(), (ignored) -> {
|
||||
val c = new Configuration(configDir.resolve(cfg.modid() + ".cfg").toFile());
|
||||
c.load();
|
||||
@@ -61,103 +70,74 @@ public class ConfigurationManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the configuration into a list of config elements usable in config GUI code.
|
||||
* @param configClass The class to process.
|
||||
* @return The configuration elements.
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public static List<IConfigElement> getConfigElements(Class<?> configClass) throws ConfigException {
|
||||
val cfg = Optional
|
||||
.ofNullable(configClass.getAnnotation(Config.class))
|
||||
.orElseThrow(() -> new ConfigException("Class " + configClass.getName() + " does not have a @Config annotation!"));
|
||||
val rawConfig = Optional
|
||||
.ofNullable(configs.get(cfg.modid()))
|
||||
.map((conf) -> Optional.ofNullable(configToClassMap.get(conf))
|
||||
.map((l) -> l.contains(configClass))
|
||||
.orElse(false) ? conf : null)
|
||||
.orElseThrow(() -> new ConfigException("Tried to get config elements for non-registed config class!"));
|
||||
val category = cfg.category();
|
||||
val elements = new ConfigElement<>(rawConfig.getCategory(category)).getChildElements();
|
||||
return elements.stream().map((element) -> new IConfigElementProxy(element, () -> {
|
||||
try {
|
||||
processConfigInternal(configClass, category, rawConfig);
|
||||
rawConfig.save();
|
||||
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException |
|
||||
NoSuchFieldException | ConfigException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
})).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal, do not use.
|
||||
*/
|
||||
public static void init() {
|
||||
if (initialized) return;
|
||||
configDir = CoreLoadingPlugin.mcDir.toPath().resolve("config");
|
||||
FMLCommonHandler.instance().bus().register(instance);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal, do not use.
|
||||
* @param event The event.
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public void onConfigChanged(ConfigChangedEvent.OnConfigChangedEvent event) {
|
||||
val config = configs.get(event.modID);
|
||||
if (config == null)
|
||||
return;
|
||||
val configClasses = configToClassMap.get(config);
|
||||
configClasses.forEach((configClass) -> {
|
||||
try {
|
||||
val category = Optional.ofNullable(configClass.getAnnotation(Config.class)).map(Config::category).orElseThrow(() -> new ConfigException("Failed to get config category for class " + configClass.getName()));
|
||||
processConfigInternal(configClass, category, config);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
private static void processConfigInternal(Class<?> configClass, String category, Configuration rawConfig) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException, ConfigException {
|
||||
private static void processConfigInternal(Class<?> configClass, String category, Configuration rawConfig)
|
||||
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException,
|
||||
ConfigException {
|
||||
val cat = rawConfig.getCategory(category);
|
||||
for (val field: configClass.getDeclaredFields()) {
|
||||
if (field.getAnnotation(Config.Ignore.class) != null) continue;
|
||||
for (val field : configClass.getDeclaredFields()) {
|
||||
if (field.getAnnotation(Config.Ignore.class) != null) {
|
||||
continue;
|
||||
}
|
||||
field.setAccessible(true);
|
||||
val comment = Optional.ofNullable(field.getAnnotation(Config.Comment.class)).map(Config.Comment::value).map((lines) -> String.join("\n", lines)).orElse("");
|
||||
val name = Optional.ofNullable(field.getAnnotation(Config.Name.class)).map(Config.Name::value).orElse(field.getName());
|
||||
val langKey = Optional.ofNullable(field.getAnnotation(Config.LangKey.class)).map(Config.LangKey::value).orElse(name);
|
||||
val comment = Optional.ofNullable(field.getAnnotation(Config.Comment.class))
|
||||
.map(Config.Comment::value)
|
||||
.map((lines) -> String.join("\n", lines))
|
||||
.orElse("");
|
||||
val name = Optional.ofNullable(field.getAnnotation(Config.Name.class))
|
||||
.map(Config.Name::value)
|
||||
.orElse(field.getName());
|
||||
val langKey = Optional.ofNullable(field.getAnnotation(Config.LangKey.class))
|
||||
.map(Config.LangKey::value)
|
||||
.orElse(name);
|
||||
val fieldClass = field.getType();
|
||||
var boxed = false;
|
||||
if ((boxed = fieldClass.equals(Boolean.class)) || fieldClass.equals(boolean.class)) {
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultBoolean.class)).map(Config.DefaultBoolean::value).orElse(boxed ? (Boolean) field.get(null) : field.getBoolean(null));
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultBoolean.class))
|
||||
.map(Config.DefaultBoolean::value)
|
||||
.orElse(boxed ? (Boolean) field.get(null) : field.getBoolean(null));
|
||||
field.setBoolean(null, rawConfig.getBoolean(name, category, defaultValue, comment, langKey));
|
||||
} else if ((boxed = fieldClass.equals(Integer.class)) || fieldClass.equals(int.class)) {
|
||||
val range = Optional.ofNullable(field.getAnnotation(Config.RangeInt.class));
|
||||
val min = range.map(Config.RangeInt::min).orElse(Integer.MIN_VALUE);
|
||||
val max = range.map(Config.RangeInt::max).orElse(Integer.MAX_VALUE);
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultInt.class)).map(Config.DefaultInt::value).orElse(boxed ? (Integer)field.get(null) : field.getInt(null));
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultInt.class))
|
||||
.map(Config.DefaultInt::value)
|
||||
.orElse(boxed ? (Integer) field.get(null) : field.getInt(null));
|
||||
field.setInt(null, rawConfig.getInt(name, category, defaultValue, min, max, comment, langKey));
|
||||
} else if ((boxed = fieldClass.equals(Float.class)) || fieldClass.equals(float.class)) {
|
||||
val range = Optional.ofNullable(field.getAnnotation(Config.RangeFloat.class));
|
||||
val min = range.map(Config.RangeFloat::min).orElse(Float.MIN_VALUE);
|
||||
val max = range.map(Config.RangeFloat::max).orElse(Float.MAX_VALUE);
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultFloat.class)).map(Config.DefaultFloat::value).orElse(boxed ? (Float) field.get(null) : field.getFloat(null));
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultFloat.class))
|
||||
.map(Config.DefaultFloat::value)
|
||||
.orElse(boxed ? (Float) field.get(null) : field.getFloat(null));
|
||||
field.setFloat(null, rawConfig.getFloat(name, category, defaultValue, min, max, comment, langKey));
|
||||
} else if (fieldClass.equals(String.class)) {
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultString.class)).map(Config.DefaultString::value).orElse((String)field.get(null));
|
||||
val pattern = Optional.ofNullable(field.getAnnotation(Config.Pattern.class)).map(Config.Pattern::value).map(Pattern::compile).orElse(null);
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultString.class))
|
||||
.map(Config.DefaultString::value)
|
||||
.orElse((String) field.get(null));
|
||||
val pattern = Optional.ofNullable(field.getAnnotation(Config.Pattern.class))
|
||||
.map(Config.Pattern::value)
|
||||
.map(Pattern::compile)
|
||||
.orElse(null);
|
||||
field.set(null, rawConfig.getString(name, category, defaultValue, comment, langKey, pattern));
|
||||
} else if (fieldClass.isEnum()) {
|
||||
val enumValues = Arrays.stream((Object[])fieldClass.getDeclaredMethod("values").invoke(null)).map((obj) -> (Enum<?>)obj).collect(Collectors.toList());
|
||||
val defaultValue = (Enum<?>)
|
||||
Optional.ofNullable(field.getAnnotation(Config.DefaultEnum.class))
|
||||
.map(Config.DefaultEnum::value)
|
||||
.map((defName) -> extractField(fieldClass, defName))
|
||||
.map(ConfigurationManager::extractValue)
|
||||
.orElse(field.get(null));
|
||||
val enumValues = Arrays.stream((Object[]) fieldClass.getDeclaredMethod("values").invoke(null))
|
||||
.map((obj) -> (Enum<?>) obj)
|
||||
.collect(Collectors.toList());
|
||||
val defaultValue = (Enum<?>) Optional.ofNullable(field.getAnnotation(Config.DefaultEnum.class))
|
||||
.map(Config.DefaultEnum::value)
|
||||
.map((defName) -> extractField(fieldClass, defName))
|
||||
.map(ConfigurationManager::extractValue)
|
||||
.orElse(field.get(null));
|
||||
val possibleValues = enumValues.stream().map(Enum::name).toArray(String[]::new);
|
||||
var value = rawConfig.getString(name, category, defaultValue.name(), comment + "\nPossible values: " + Arrays.toString(possibleValues) + "\n", possibleValues, langKey);
|
||||
var value = rawConfig.getString(name,
|
||||
category,
|
||||
defaultValue.name(),
|
||||
comment + "\nPossible values: " + Arrays.toString(possibleValues) +
|
||||
"\n",
|
||||
possibleValues,
|
||||
langKey);
|
||||
|
||||
try {
|
||||
if (!Arrays.asList(possibleValues).contains(value)) {
|
||||
@@ -169,11 +149,16 @@ public class ConfigurationManager {
|
||||
}
|
||||
field.set(null, enumField.get(null));
|
||||
} catch (NoSuchFieldException e) {
|
||||
FalsePatternLib.getLog().warn("Invalid value " + value + " for enum configuration field " + field.getName() + " of type " + fieldClass.getName() + " in config class " + configClass.getName() + "! Using default value of " + defaultValue + "!");
|
||||
FalsePatternLib.getLog()
|
||||
.warn("Invalid value " + value + " for enum configuration field " + field.getName() +
|
||||
" of type " + fieldClass.getName() + " in config class " +
|
||||
configClass.getName() + "! Using default value of " + defaultValue + "!");
|
||||
field.set(null, defaultValue);
|
||||
}
|
||||
} else {
|
||||
throw new ConfigException("Illegal config field: " + field.getName() + " in " + configClass.getName() + ": Unsupported type " + fieldClass.getName() + "! Did you forget an @Ignore annotation?");
|
||||
throw new ConfigException("Illegal config field: " + field.getName() + " in " + configClass.getName() +
|
||||
": Unsupported type " + fieldClass.getName() +
|
||||
"! Did you forget an @Ignore annotation?");
|
||||
}
|
||||
if (field.isAnnotationPresent(Config.RequiresMcRestart.class)) {
|
||||
cat.setRequiresMcRestart(true);
|
||||
@@ -193,4 +178,75 @@ public class ConfigurationManager {
|
||||
private static Object extractValue(Field field) {
|
||||
return field.get(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the configuration into a list of config elements usable in config GUI code.
|
||||
*
|
||||
* @param configClass The class to process.
|
||||
*
|
||||
* @return The configuration elements.
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public static List<IConfigElement> getConfigElements(Class<?> configClass) throws ConfigException {
|
||||
val cfg = Optional.ofNullable(configClass.getAnnotation(Config.class))
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Class " + configClass.getName() + " does not have a @Config annotation!"));
|
||||
val rawConfig = Optional.ofNullable(configs.get(cfg.modid()))
|
||||
.map((conf) -> Optional.ofNullable(configToClassMap.get(conf))
|
||||
.map((l) -> l.contains(configClass))
|
||||
.orElse(false) ? conf : null)
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Tried to get config elements for non-registed config class!"));
|
||||
val category = cfg.category();
|
||||
val elements = new ConfigElement<>(rawConfig.getCategory(category)).getChildElements();
|
||||
return elements.stream().map((element) -> new IConfigElementProxy(element, () -> {
|
||||
try {
|
||||
processConfigInternal(configClass, category, rawConfig);
|
||||
rawConfig.save();
|
||||
} catch (IllegalAccessException |
|
||||
NoSuchMethodException |
|
||||
InvocationTargetException |
|
||||
NoSuchFieldException |
|
||||
ConfigException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
})).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal, do not use.
|
||||
*/
|
||||
public static void init() {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
configDir = CoreLoadingPlugin.mcDir.toPath().resolve("config");
|
||||
FMLCommonHandler.instance().bus().register(instance);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal, do not use.
|
||||
*
|
||||
* @param event The event.
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public void onConfigChanged(ConfigChangedEvent.OnConfigChangedEvent event) {
|
||||
val config = configs.get(event.modID);
|
||||
if (config == null) {
|
||||
return;
|
||||
}
|
||||
val configClasses = configToClassMap.get(config);
|
||||
configClasses.forEach((configClass) -> {
|
||||
try {
|
||||
val category = Optional.ofNullable(configClass.getAnnotation(Config.class))
|
||||
.map(Config::category)
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Failed to get config category for class " + configClass.getName()));
|
||||
processConfigInternal(configClass, category, config);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,13 @@ import cpw.mods.fml.client.config.ConfigGuiType;
|
||||
import cpw.mods.fml.client.config.GuiConfigEntries;
|
||||
import cpw.mods.fml.client.config.GuiEditArrayEntries;
|
||||
import cpw.mods.fml.client.config.IConfigElement;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class IConfigElementProxy<T> implements IConfigElement<T> {
|
||||
private final IConfigElement<T> proxied;
|
||||
private final Runnable onUpdate;
|
||||
|
||||
public IConfigElementProxy(IConfigElement<T> proxied, Runnable onUpdate) {
|
||||
this.proxied = proxied;
|
||||
this.onUpdate = onUpdate;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.falsepattern.lib.dependencies;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
|
||||
@StableAPI(since = "0.6.0")
|
||||
public class ComplexVersion extends Version {
|
||||
final Version[] versions;
|
||||
|
||||
public ComplexVersion(@NonNull Version mainVersion, Version... subVersions) {
|
||||
this.versions = new Version[subVersions.length + 1];
|
||||
this.versions[0] = mainVersion;
|
||||
@@ -23,7 +23,9 @@ public class ComplexVersion extends Version {
|
||||
int count = Math.min(versions.length, other.versions.length);
|
||||
for (int i = 0; i < count; i++) {
|
||||
val result = versions[i].compareTo(other.versions[i]);
|
||||
if (result != 0) return result;
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (versions.length != other.versions.length) {
|
||||
return versions.length - other.versions.length;
|
||||
|
||||
@@ -3,16 +3,22 @@ package com.falsepattern.lib.dependencies;
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import com.falsepattern.lib.internal.CoreLoadingPlugin;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
import lombok.var;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@StableAPI(since = "0.6.0")
|
||||
public class DependencyLoader {
|
||||
@@ -25,39 +31,66 @@ public class DependencyLoader {
|
||||
mavenRepositories.add(url);
|
||||
}
|
||||
|
||||
public static void loadLibrary(String loadingModId, String groupId, String artifactId, @NonNull Version minVersion, Version maxVersion, @NonNull Version preferredVersion, String regularSuffix, String devSuffix) {
|
||||
public static void loadLibrary(String loadingModId,
|
||||
String groupId,
|
||||
String artifactId,
|
||||
@NonNull Version minVersion,
|
||||
Version maxVersion,
|
||||
@NonNull Version preferredVersion,
|
||||
String regularSuffix,
|
||||
String devSuffix) {
|
||||
val suffix = FalsePatternLib.isDeveloperEnvironment() ? devSuffix : regularSuffix;
|
||||
FalsePatternLib.getLog().info("Adding library {}:{}:{}{}, requested by mod {}", groupId, artifactId, preferredVersion, suffix != null ? "-" + suffix : "", loadingModId);
|
||||
FalsePatternLib.getLog()
|
||||
.info("Adding library {}:{}:{}{}, requested by mod {}",
|
||||
groupId,
|
||||
artifactId,
|
||||
preferredVersion,
|
||||
suffix != null ? "-" + suffix : "",
|
||||
loadingModId);
|
||||
var artifact = groupId + ":" + artifactId + ":" + suffix;
|
||||
if (loadedLibraries.containsKey(artifact)) {
|
||||
val currentVer = loadedLibraries.get(artifact);
|
||||
if (currentVer.equals(preferredVersion)) return;
|
||||
if (currentVer.equals(preferredVersion)) {
|
||||
return;
|
||||
}
|
||||
val rangeString = "(minimum: " + minVersion + (maxVersion == null ? "" : ", maximum: " + maxVersion) + ")";
|
||||
if (minVersion.compareTo(currentVer) > 0 || (maxVersion != null && maxVersion.compareTo(currentVer) < 0)) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
FalsePatternLib.getLog().fatal("ALERT VVVVVVVVVVVV ALERT");
|
||||
}
|
||||
FalsePatternLib.getLog().fatal("Library {}:{}{} already loaded with version {}, " +
|
||||
"but a version in the range {} was requested! Thing may go horribly wrong! " +
|
||||
"Requested by mod: {}, previously loaded by mod: {}",
|
||||
groupId, artifactId, suffix != null ? ":" + suffix : "", currentVer,
|
||||
rangeString,
|
||||
loadingModId, loadedLibraryMods.get(artifact));
|
||||
FalsePatternLib.getLog()
|
||||
.fatal("Library {}:{}{} already loaded with version {}, " +
|
||||
"but a version in the range {} was requested! Thing may go horribly wrong! " +
|
||||
"Requested by mod: {}, previously loaded by mod: {}",
|
||||
groupId,
|
||||
artifactId,
|
||||
suffix != null ? ":" + suffix : "",
|
||||
currentVer,
|
||||
rangeString,
|
||||
loadingModId,
|
||||
loadedLibraryMods.get(artifact));
|
||||
for (int i = 0; i < 16; i++) {
|
||||
FalsePatternLib.getLog().fatal("ALERT ^^^^^^^^^^^^ ALERT");
|
||||
}
|
||||
} else {
|
||||
FalsePatternLib.getLog().info("Attempted loading of library {}:{}{} with preferred version {}, " +
|
||||
"but version {} was already loaded, which matched the range {}. This is not an error. " +
|
||||
"Requested by mod: {}, previously loaded by mod: {}",
|
||||
groupId, artifactId, suffix != null ? ":" + suffix : "", preferredVersion,
|
||||
currentVer, rangeString,
|
||||
loadingModId, loadedLibraryMods.get(artifact));
|
||||
FalsePatternLib.getLog()
|
||||
.info("Attempted loading of library {}:{}{} with preferred version {}, " +
|
||||
"but version {} was already loaded, which matched the range {}. This is not an " +
|
||||
"error. " + "Requested by mod: {}, previously loaded by mod: {}",
|
||||
groupId,
|
||||
artifactId,
|
||||
suffix != null ? ":" + suffix : "",
|
||||
preferredVersion,
|
||||
currentVer,
|
||||
rangeString,
|
||||
loadingModId,
|
||||
loadedLibraryMods.get(artifact));
|
||||
}
|
||||
return;
|
||||
}
|
||||
val modsDir = new File(CoreLoadingPlugin.mcDir, "mods");
|
||||
val mavenJarName = String.format("%s-%s%s.jar", artifactId, preferredVersion, (suffix != null) ? ("-" + suffix) : "");
|
||||
val mavenJarName =
|
||||
String.format("%s-%s%s.jar", artifactId, preferredVersion, (suffix != null) ? ("-" + suffix) : "");
|
||||
val jarName = groupId + "-" + mavenJarName;
|
||||
val libDir = new File(modsDir, "falsepattern");
|
||||
if (!libDir.exists()) {
|
||||
@@ -68,37 +101,74 @@ public class DependencyLoader {
|
||||
try {
|
||||
addToClasspath(file);
|
||||
loadedLibraries.put(artifact, preferredVersion);
|
||||
FalsePatternLib.getLog().info("Library {}:{}:{}{} successfully loaded from disk!", groupId, artifactId, preferredVersion, (suffix != null) ? ":" + suffix : "");
|
||||
FalsePatternLib.getLog()
|
||||
.info("Library {}:{}:{}{} successfully loaded from disk!",
|
||||
groupId,
|
||||
artifactId,
|
||||
preferredVersion,
|
||||
(suffix != null) ? ":" + suffix : "");
|
||||
return;
|
||||
} catch (RuntimeException e) {
|
||||
FalsePatternLib.getLog().warn("Failed to load library {}:{}:{}{} from file! Redownloading...", groupId, artifactId, preferredVersion, (suffix != null) ? ":" + suffix : "");
|
||||
FalsePatternLib.getLog()
|
||||
.warn("Failed to load library {}:{}:{}{} from file! Redownloading...",
|
||||
groupId,
|
||||
artifactId,
|
||||
preferredVersion,
|
||||
(suffix != null) ? ":" + suffix : "");
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
for (var repo: mavenRepositories) {
|
||||
for (var repo : mavenRepositories) {
|
||||
try {
|
||||
if (!repo.endsWith("/")) repo = repo + "/";
|
||||
val url = new URL(String.format("%s%s/%s/%s/%s", repo, groupId.replace('.', '/'), artifactId, preferredVersion, mavenJarName));
|
||||
if (!repo.endsWith("/")) {
|
||||
repo = repo + "/";
|
||||
}
|
||||
val url = new URL(String.format("%s%s/%s/%s/%s",
|
||||
repo,
|
||||
groupId.replace('.', '/'),
|
||||
artifactId,
|
||||
preferredVersion,
|
||||
mavenJarName));
|
||||
|
||||
val connection = (HttpsURLConnection) url.openConnection();
|
||||
connection.setConnectTimeout(1500);
|
||||
connection.setReadTimeout(1500);
|
||||
connection.setRequestProperty("User-Agent", "FalsePatternLib Downloader");
|
||||
if (connection.getResponseCode() != 200) {
|
||||
FalsePatternLib.getLog().info("Artifact {}:{}:{}{} was not found on repo {}", groupId, artifactId, preferredVersion, (suffix != null) ? ":" + suffix : "", repo);
|
||||
FalsePatternLib.getLog()
|
||||
.info("Artifact {}:{}:{}{} was not found on repo {}",
|
||||
groupId,
|
||||
artifactId,
|
||||
preferredVersion,
|
||||
(suffix != null) ? ":" + suffix : "",
|
||||
repo);
|
||||
connection.disconnect();
|
||||
continue;
|
||||
}
|
||||
FalsePatternLib.getLog().info("Downloading {}:{}:{}{} from {}", groupId, artifactId, preferredVersion, (suffix != null) ? ":" + suffix : "", repo);
|
||||
FalsePatternLib.getLog()
|
||||
.info("Downloading {}:{}:{}{} from {}",
|
||||
groupId,
|
||||
artifactId,
|
||||
preferredVersion,
|
||||
(suffix != null) ? ":" + suffix : "",
|
||||
repo);
|
||||
download(connection.getInputStream(), file);
|
||||
FalsePatternLib.getLog().info("Downloaded {}:{}:{}{}", groupId, artifactId, preferredVersion, (suffix != null) ? ":" + suffix : "");
|
||||
FalsePatternLib.getLog()
|
||||
.info("Downloaded {}:{}:{}{}",
|
||||
groupId,
|
||||
artifactId,
|
||||
preferredVersion,
|
||||
(suffix != null) ? ":" + suffix : "");
|
||||
loadedLibraries.put(artifact, preferredVersion);
|
||||
loadedLibraryMods.put(artifact, loadingModId);
|
||||
addToClasspath(file);
|
||||
return;
|
||||
} catch (IOException ignored) {}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
val errorMessage = "Failed to download library " + groupId + ":" + artifactId + ":" + preferredVersion + ((suffix != null) ? ":" + suffix : "") + " from any repository! Requested by mod: " + loadingModId;
|
||||
val errorMessage = "Failed to download library " + groupId + ":" + artifactId + ":" + preferredVersion +
|
||||
((suffix != null) ? ":" + suffix : "") + " from any repository! Requested by mod: " +
|
||||
loadingModId;
|
||||
FalsePatternLib.getLog().fatal(errorMessage);
|
||||
throw new IllegalStateException(errorMessage);
|
||||
}
|
||||
@@ -114,7 +184,9 @@ public class DependencyLoader {
|
||||
}
|
||||
|
||||
private static void download(InputStream is, File target) throws IOException {
|
||||
if (target.exists()) return;
|
||||
if (target.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bytesRead = 0;
|
||||
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
package com.falsepattern.lib.dependencies;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import java.util.Objects;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@StableAPI(since = "0.6.0")
|
||||
public class SemanticVersion extends Version {
|
||||
@Getter
|
||||
private final int majorVersion;
|
||||
@Getter
|
||||
private final int minorVersion;
|
||||
@Getter
|
||||
private final int patchVersion;
|
||||
@Getter
|
||||
private final String preRelease;
|
||||
@Getter
|
||||
private final String build;
|
||||
@Getter private final int majorVersion;
|
||||
@Getter private final int minorVersion;
|
||||
@Getter private final int patchVersion;
|
||||
@Getter private final String preRelease;
|
||||
@Getter private final String build;
|
||||
|
||||
public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, String preRelease) {
|
||||
this(majorVersion, minorVersion, patchVersion, preRelease, null);
|
||||
}
|
||||
|
||||
@Builder
|
||||
public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, String preRelease, String build) {
|
||||
@@ -32,10 +30,6 @@ public class SemanticVersion extends Version {
|
||||
this.build = "".equals(build) ? null : build;
|
||||
}
|
||||
|
||||
public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, String preRelease) {
|
||||
this(majorVersion, minorVersion, patchVersion, preRelease, null);
|
||||
}
|
||||
|
||||
public SemanticVersion(int majorVersion, int minorVersion, int patchVersion) {
|
||||
this(majorVersion, minorVersion, patchVersion, null, null);
|
||||
}
|
||||
@@ -43,7 +37,7 @@ public class SemanticVersion extends Version {
|
||||
@Override
|
||||
public int compareTo(@NonNull Version o) {
|
||||
if (o instanceof ComplexVersion) {
|
||||
val result = this.compareTo(((ComplexVersion)o).versions[0]);
|
||||
val result = this.compareTo(((ComplexVersion) o).versions[0]);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
} else if (((ComplexVersion) o).versions.length > 1) {
|
||||
@@ -52,7 +46,7 @@ public class SemanticVersion extends Version {
|
||||
return 0;
|
||||
}
|
||||
} else if (o instanceof SemanticVersion) {
|
||||
val other = (SemanticVersion)o;
|
||||
val other = (SemanticVersion) o;
|
||||
if (majorVersion != other.majorVersion) {
|
||||
return majorVersion - other.majorVersion;
|
||||
} else if (minorVersion != other.minorVersion) {
|
||||
@@ -75,6 +69,7 @@ public class SemanticVersion extends Version {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return majorVersion + "." + minorVersion + "." + patchVersion + (preRelease == null ? "" : "-" + preRelease) + (build == null ? "" : "+" + build);
|
||||
return majorVersion + "." + minorVersion + "." + patchVersion + (preRelease == null ? "" : "-" + preRelease) +
|
||||
(build == null ? "" : "+" + build);
|
||||
}
|
||||
}
|
||||
@@ -4,15 +4,18 @@ import com.falsepattern.lib.StableAPI;
|
||||
|
||||
@StableAPI(since = "0.6.0")
|
||||
public abstract class Version implements Comparable<Version> {
|
||||
protected Version(){}
|
||||
|
||||
public boolean equals(Version other) {
|
||||
return compareTo(other) == 0;
|
||||
protected Version() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Version)) return false;
|
||||
if (!(obj instanceof Version)) {
|
||||
return false;
|
||||
}
|
||||
return equals((Version) obj);
|
||||
}
|
||||
|
||||
public boolean equals(Version other) {
|
||||
return compareTo(other) == 0;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.Name;
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.SortingIndex;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -31,7 +30,7 @@ public class CoreLoadingPlugin implements IFMLLoadingPlugin {
|
||||
|
||||
@Override
|
||||
public void injectData(Map<String, Object> data) {
|
||||
mcDir = (File)data.get("mcLocation");
|
||||
mcDir = (File) data.get("mcLocation");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,17 +14,18 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Utility class used by FalsePatternLib's internal code. This can change between versions without notice, so do not use this in your code!
|
||||
* Utility class used by FalsePatternLib's internal code. This can change between versions without notice, so do not use
|
||||
* this in your code!
|
||||
*/
|
||||
public class FalsePatternLib extends DummyModContainer {
|
||||
@Getter
|
||||
private static final Logger log = LogManager.getLogger(Tags.MODNAME);
|
||||
@Getter private static final Logger log = LogManager.getLogger(Tags.MODNAME);
|
||||
|
||||
@Getter
|
||||
private static final boolean developerEnvironment = (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment");
|
||||
@Getter private static final boolean developerEnvironment =
|
||||
(boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment");
|
||||
|
||||
public FalsePatternLib() {
|
||||
super(MetadataCollection.from(ResourceUtil.getResourceFromJar("/mcmod.info", FalsePatternLib.class), Tags.MODID).getMetadataForId(Tags.MODID, null));
|
||||
super(MetadataCollection.from(ResourceUtil.getResourceFromJar("/mcmod.info", FalsePatternLib.class), Tags.MODID)
|
||||
.getMetadataForId(Tags.MODID, null));
|
||||
log.info("Version " + Tags.VERSION + " initialized!");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
package com.falsepattern.lib.mixin;
|
||||
|
||||
import cpw.mods.fml.relauncher.FMLLaunchHandler;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import lombok.val;
|
||||
|
||||
public interface IMixin {
|
||||
|
||||
Side getSide();
|
||||
String getMixin();
|
||||
Predicate<List<ITargetedMod>> getFilter();
|
||||
|
||||
default boolean shouldLoad(List<ITargetedMod> loadedMods) {
|
||||
val side = getSide();
|
||||
return (side == Side.COMMON
|
||||
|| side == Side.SERVER && FMLLaunchHandler.side().isServer()
|
||||
|| side == Side.CLIENT && FMLLaunchHandler.side().isClient())
|
||||
&& getFilter().test(loadedMods);
|
||||
return (side == Side.COMMON || side == Side.SERVER && FMLLaunchHandler.side().isServer() ||
|
||||
side == Side.CLIENT && FMLLaunchHandler.side().isClient()) && getFilter().test(loadedMods);
|
||||
}
|
||||
|
||||
Side getSide();
|
||||
|
||||
Predicate<List<ITargetedMod>> getFilter();
|
||||
|
||||
enum Side {
|
||||
COMMON,
|
||||
CLIENT,
|
||||
SERVER
|
||||
}
|
||||
|
||||
final class PredicateHelpers {
|
||||
@@ -42,10 +47,4 @@ public interface IMixin {
|
||||
return (list) -> !list.contains(mod);
|
||||
}
|
||||
}
|
||||
|
||||
enum Side {
|
||||
COMMON,
|
||||
CLIENT,
|
||||
SERVER
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,6 @@
|
||||
package com.falsepattern.lib.mixin;
|
||||
|
||||
import com.falsepattern.lib.internal.CoreLoadingPlugin;
|
||||
import lombok.val;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spongepowered.asm.lib.tree.ClassNode;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
@@ -18,16 +10,19 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.val;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spongepowered.asm.lib.tree.ClassNode;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
|
||||
import static java.nio.file.Files.walk;
|
||||
|
||||
public interface IMixinPlugin extends IMixinConfigPlugin {
|
||||
Path MODS_DIRECTORY_PATH = CoreLoadingPlugin.mcDir.toPath().resolve("mods");
|
||||
|
||||
Logger getLogger();
|
||||
ITargetedMod[] getTargetedModEnumValues();
|
||||
IMixin[] getMixinEnumValues();
|
||||
|
||||
static Logger createLogger(String modName) {
|
||||
return LogManager.getLogger(modName + " Mixin Loader");
|
||||
}
|
||||
@@ -57,15 +52,13 @@ public interface IMixinPlugin extends IMixinConfigPlugin {
|
||||
val isDevelopmentEnvironment = (boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment");
|
||||
val targetedMods = getTargetedModEnumValues();
|
||||
val loadedMods = Arrays.stream(targetedMods)
|
||||
.filter(mod -> (mod.isLoadInDevelopment() && isDevelopmentEnvironment)
|
||||
|| loadJarOf(mod))
|
||||
.filter(mod -> (mod.isLoadInDevelopment() && isDevelopmentEnvironment) || loadJarOf(mod))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (val mod : targetedMods) {
|
||||
if(loadedMods.contains(mod)) {
|
||||
if (loadedMods.contains(mod)) {
|
||||
getLogger().info("Found " + mod.getModName() + "! Integrating now...");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
getLogger().info("Could not find " + mod.getModName() + "! Skipping integration....");
|
||||
}
|
||||
}
|
||||
@@ -81,27 +74,19 @@ public interface IMixinPlugin extends IMixinConfigPlugin {
|
||||
return mixins;
|
||||
}
|
||||
|
||||
@Override
|
||||
default void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
default void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
|
||||
}
|
||||
ITargetedMod[] getTargetedModEnumValues();
|
||||
|
||||
default boolean loadJarOf(final ITargetedMod mod) {
|
||||
boolean success = false;
|
||||
try {
|
||||
File jar = findJarOf(mod);
|
||||
if(jar == null) {
|
||||
if (jar == null) {
|
||||
getLogger().info("Jar not found for " + mod);
|
||||
return false;
|
||||
}
|
||||
getLogger().info("Attempting to add " + jar + " to the URL Class Path");
|
||||
success = true;
|
||||
if(!jar.exists()) {
|
||||
if (!jar.exists()) {
|
||||
success = false;
|
||||
throw new FileNotFoundException(jar.toString());
|
||||
}
|
||||
@@ -112,17 +97,26 @@ public interface IMixinPlugin extends IMixinConfigPlugin {
|
||||
return success;
|
||||
}
|
||||
|
||||
Logger getLogger();
|
||||
|
||||
IMixin[] getMixinEnumValues();
|
||||
|
||||
static File findJarOf(final ITargetedMod mod) {
|
||||
try {
|
||||
return walk(MODS_DIRECTORY_PATH)
|
||||
.filter(mod::isMatchingJar)
|
||||
.map(Path::toFile)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
catch (IOException e) {
|
||||
return walk(MODS_DIRECTORY_PATH).filter(mod::isMatchingJar).map(Path::toFile).findFirst().orElse(null);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
default void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
package com.falsepattern.lib.mixin;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public interface ITargetedMod {
|
||||
|
||||
String getModName();
|
||||
Predicate<String> getCondition();
|
||||
|
||||
boolean isLoadInDevelopment();
|
||||
|
||||
default boolean isMatchingJar(Path path) {
|
||||
@@ -19,6 +18,8 @@ public interface ITargetedMod {
|
||||
return "jar".equals(fileExtension) && getCondition().test(nameLowerCase);
|
||||
}
|
||||
|
||||
Predicate<String> getCondition();
|
||||
|
||||
final class PredicateHelpers {
|
||||
public static Predicate<String> startsWith(String subString) {
|
||||
return (name) -> name.startsWith(subString);
|
||||
|
||||
@@ -2,24 +2,23 @@ package com.falsepattern.lib.mixin;
|
||||
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.ModClassLoader;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.val;
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Backport from spongemixins 1.3 for compat with the curseforge 1.2.0 version.
|
||||
*
|
||||
* <p>
|
||||
* Also added Grimoire protection.
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class MinecraftURLClassPath {
|
||||
/**
|
||||
* Utility to manipulate the minecraft URL ClassPath
|
||||
* Utility to manipulate the minecraft URL ClassPath
|
||||
*/
|
||||
|
||||
private static final Object ucp;
|
||||
@@ -65,11 +64,12 @@ public final class MinecraftURLClassPath {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Jar to the Minecraft URL ClassPath
|
||||
* - Needed when using mixins on classes outside of Minecraft or other coremods
|
||||
* Adds a Jar to the Minecraft URL ClassPath - Needed when using mixins on classes outside of Minecraft or other
|
||||
* coremods
|
||||
*/
|
||||
public static void addJar(File pathToJar) throws Exception {
|
||||
if (!GRIMOIRE)
|
||||
if (!GRIMOIRE) {
|
||||
addURL.invoke(ucp, pathToJar.toURI().toURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,15 @@ package com.falsepattern.lib.text;
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import java.awt.Color;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import lombok.NonNull;
|
||||
import lombok.val;
|
||||
import lombok.var;
|
||||
@@ -19,11 +28,6 @@ import net.minecraft.util.ChatStyle;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Universal escape sequence-based text rendering and chat messages.
|
||||
*/
|
||||
@@ -33,35 +37,69 @@ public final class FormattedText {
|
||||
private static final Map<EnumChatFormatting, Color> colorMap = new HashMap<>();
|
||||
|
||||
private static final char ESCAPE = '\u00a7';
|
||||
|
||||
static {
|
||||
for (val value: EnumChatFormatting.values()) {
|
||||
for (val value : EnumChatFormatting.values()) {
|
||||
reverseMap.put(value.getFormattingCode(), value);
|
||||
if (value.isColor()) {
|
||||
final int rgb;
|
||||
switch (value.getFormattingCode()) {
|
||||
default: rgb = 0x000000; break;
|
||||
case '1': rgb = 0x0000AA; break;
|
||||
case '2': rgb = 0x00AA00; break;
|
||||
case '3': rgb = 0x00AAAA; break;
|
||||
case '4': rgb = 0xAA0000; break;
|
||||
case '5': rgb = 0xAA00AA; break;
|
||||
case '6': rgb = 0xFFAA00; break;
|
||||
case '7': rgb = 0xAAAAAA; break;
|
||||
case '8': rgb = 0x555555; break;
|
||||
case '9': rgb = 0x5555FF; break;
|
||||
case 'a': rgb = 0x55FF55; break;
|
||||
case 'b': rgb = 0x55FFFF; break;
|
||||
case 'c': rgb = 0xFF5555; break;
|
||||
case 'd': rgb = 0xFF55FF; break;
|
||||
case 'e': rgb = 0xFFFF55; break;
|
||||
case 'f': rgb = 0xFFFFFF; break;
|
||||
default:
|
||||
rgb = 0x000000;
|
||||
break;
|
||||
case '1':
|
||||
rgb = 0x0000AA;
|
||||
break;
|
||||
case '2':
|
||||
rgb = 0x00AA00;
|
||||
break;
|
||||
case '3':
|
||||
rgb = 0x00AAAA;
|
||||
break;
|
||||
case '4':
|
||||
rgb = 0xAA0000;
|
||||
break;
|
||||
case '5':
|
||||
rgb = 0xAA00AA;
|
||||
break;
|
||||
case '6':
|
||||
rgb = 0xFFAA00;
|
||||
break;
|
||||
case '7':
|
||||
rgb = 0xAAAAAA;
|
||||
break;
|
||||
case '8':
|
||||
rgb = 0x555555;
|
||||
break;
|
||||
case '9':
|
||||
rgb = 0x5555FF;
|
||||
break;
|
||||
case 'a':
|
||||
rgb = 0x55FF55;
|
||||
break;
|
||||
case 'b':
|
||||
rgb = 0x55FFFF;
|
||||
break;
|
||||
case 'c':
|
||||
rgb = 0xFF5555;
|
||||
break;
|
||||
case 'd':
|
||||
rgb = 0xFF55FF;
|
||||
break;
|
||||
case 'e':
|
||||
rgb = 0xFFFF55;
|
||||
break;
|
||||
case 'f':
|
||||
rgb = 0xFFFFFF;
|
||||
break;
|
||||
}
|
||||
colorMap.put(value, new Color(rgb));
|
||||
}
|
||||
try {
|
||||
Field colorF = Color.class.getDeclaredField(value.getFriendlyName());
|
||||
colorMap.put(value, (Color)colorF.get(null));
|
||||
} catch (NoSuchFieldException | IllegalAccessException ignored) {}
|
||||
colorMap.put(value, (Color) colorF.get(null));
|
||||
} catch (NoSuchFieldException | IllegalAccessException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +112,10 @@ public final class FormattedText {
|
||||
|
||||
private final boolean endLine;
|
||||
|
||||
private FormattedText(@NonNull String text, @NonNull EnumChatFormatting colorStyle, @NonNull Set<EnumChatFormatting> fancyStyles, boolean endLine) {
|
||||
private FormattedText(@NonNull String text,
|
||||
@NonNull EnumChatFormatting colorStyle,
|
||||
@NonNull Set<EnumChatFormatting> fancyStyles,
|
||||
boolean endLine) {
|
||||
this.text = text;
|
||||
this.fancyStyles.addAll(fancyStyles);
|
||||
this.colorStyle = colorStyle;
|
||||
@@ -84,7 +125,9 @@ public final class FormattedText {
|
||||
/**
|
||||
* Parse a string with minecraft style escapes (\u00a7X) into a {@link FormattedText} instance, which can then be
|
||||
* used to generate chat or render-able text.
|
||||
*
|
||||
* @param text The string to parse
|
||||
*
|
||||
* @return The parsed text structure
|
||||
*/
|
||||
public static FormattedText parse(String text) {
|
||||
@@ -98,8 +141,9 @@ public final class FormattedText {
|
||||
char c = text.charAt(i);
|
||||
if (format) {
|
||||
val f = reverseMap.get(c);
|
||||
if (f == null)
|
||||
if (f == null) {
|
||||
continue;
|
||||
}
|
||||
if (f == EnumChatFormatting.RESET) {
|
||||
currentColorStyle = EnumChatFormatting.WHITE;
|
||||
currentFancyStyle.clear();
|
||||
@@ -114,10 +158,11 @@ public final class FormattedText {
|
||||
if (c == ESCAPE || c == '\n') {
|
||||
format = c == ESCAPE;
|
||||
val txt = new FormattedText(accumulator.toString(), currentColorStyle, currentFancyStyle, c == '\n');
|
||||
if (result == null)
|
||||
if (result == null) {
|
||||
result = txt;
|
||||
else
|
||||
} else {
|
||||
result.siblings.add(txt);
|
||||
}
|
||||
accumulator.setLength(0);
|
||||
continue;
|
||||
}
|
||||
@@ -125,16 +170,29 @@ public final class FormattedText {
|
||||
}
|
||||
if (accumulator.length() > 0) {
|
||||
val txt = new FormattedText(accumulator.toString(), currentColorStyle, currentFancyStyle, true);
|
||||
if (result == null)
|
||||
if (result == null) {
|
||||
result = txt;
|
||||
else
|
||||
} else {
|
||||
result.siblings.add(txt);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addChatMessage(ICommandSender target) {
|
||||
addChatMessage(target::addChatMessage);
|
||||
}
|
||||
|
||||
private void addChatMessage(Consumer<IChatComponent> consumer) {
|
||||
for (val line : toChatText()) {
|
||||
consumer.accept(line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this text structure into chat components that can be sent to the client. This is a list, because chat components can't have newlines.
|
||||
* Converts this text structure into chat components that can be sent to the client. This is a list, because chat
|
||||
* components can't have newlines.
|
||||
*
|
||||
* @return The chat component.
|
||||
*/
|
||||
public List<ChatComponentText> toChatText() {
|
||||
@@ -142,7 +200,7 @@ public final class FormattedText {
|
||||
val result = new ArrayList<ChatComponentText>();
|
||||
result.add(thisComponent);
|
||||
FormattedText prevSibling = this;
|
||||
for (val sibling: siblings) {
|
||||
for (val sibling : siblings) {
|
||||
val siblingResult = sibling.toChatTextSingle();
|
||||
if (prevSibling.endLine) {
|
||||
result.add(thisComponent = siblingResult);
|
||||
@@ -160,7 +218,7 @@ public final class FormattedText {
|
||||
if (colorStyle != null) {
|
||||
style.setColor(colorStyle);
|
||||
}
|
||||
for (val fancyStyle: fancyStyles) {
|
||||
for (val fancyStyle : fancyStyles) {
|
||||
switch (fancyStyle) {
|
||||
case OBFUSCATED:
|
||||
style.setObfuscated(true);
|
||||
@@ -183,16 +241,6 @@ public final class FormattedText {
|
||||
return thisComponent;
|
||||
}
|
||||
|
||||
private void addChatMessage(Consumer<IChatComponent> consumer) {
|
||||
for (val line: toChatText()) {
|
||||
consumer.accept(line);
|
||||
}
|
||||
}
|
||||
|
||||
public void addChatMessage(ICommandSender target) {
|
||||
addChatMessage(target::addChatMessage);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void addChatMessage(EntityOtherPlayerMP target) {
|
||||
addChatMessage(target::addChatMessage);
|
||||
@@ -221,33 +269,23 @@ public final class FormattedText {
|
||||
|
||||
/**
|
||||
* {@link #draw(FontRenderer, int, int, boolean)} without drop shadows.
|
||||
*
|
||||
* @param renderer The font renderer to use
|
||||
* @param x Left side
|
||||
* @param y Top side
|
||||
* @param x Left side
|
||||
* @param y Top side
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void draw(FontRenderer renderer, int x, int y) {
|
||||
draw(renderer, x, y, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link #draw(FontRenderer, int, int, boolean)} with drop shadows.
|
||||
* @param renderer The font renderer to use
|
||||
* @param x Left side
|
||||
* @param y Top side
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void drawWithShadow(FontRenderer renderer, int x, int y) {
|
||||
draw(renderer, x, y, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this structure as GUI text.
|
||||
*
|
||||
* @param renderer The font renderer to use
|
||||
* @param x Left side
|
||||
* @param y Top side
|
||||
* @param shadow Whether to have drop shadow under the text
|
||||
* @param x Left side
|
||||
* @param y Top side
|
||||
* @param shadow Whether to have drop shadow under the text
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void draw(FontRenderer renderer, int x, int y, boolean shadow) {
|
||||
@@ -257,7 +295,7 @@ public final class FormattedText {
|
||||
y += renderer.FONT_HEIGHT;
|
||||
x = startX;
|
||||
}
|
||||
for (val sibling: siblings) {
|
||||
for (val sibling : siblings) {
|
||||
x = renderer.drawString(sibling.text, x, y, colorMap.get(sibling.colorStyle).getRGB(), shadow);
|
||||
if (sibling.endLine) {
|
||||
y += renderer.FONT_HEIGHT;
|
||||
@@ -265,4 +303,16 @@ public final class FormattedText {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link #draw(FontRenderer, int, int, boolean)} with drop shadows.
|
||||
*
|
||||
* @param renderer The font renderer to use
|
||||
* @param x Left side
|
||||
* @param y Top side
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void drawWithShadow(FontRenderer renderer, int x, int y) {
|
||||
draw(renderer, x, y, true);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.falsepattern.lib.util;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import lombok.val;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
@@ -10,6 +8,7 @@ import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import lombok.val;
|
||||
|
||||
/**
|
||||
* A utility class for reading resources in many ways.
|
||||
@@ -18,10 +17,14 @@ import java.nio.charset.StandardCharsets;
|
||||
public class ResourceUtil {
|
||||
|
||||
/**
|
||||
* Reads a resource as a string, using the {@link StandardCharsets#UTF_8} charset, from a specific jar file. See {@link #getResourceFromJar(String, Class)}.
|
||||
* @param resourcePath The resource to read
|
||||
* Reads a resource as a string, using the {@link StandardCharsets#UTF_8} charset, from a specific jar file. See
|
||||
* {@link #getResourceFromJar(String, Class)}.
|
||||
*
|
||||
* @param resourcePath The resource to read
|
||||
* @param referenceClass The class, from whose jar to get the resource from
|
||||
*
|
||||
* @return The string from the resource
|
||||
*
|
||||
* @throws IOException From {@link #readBytes(InputStream)}
|
||||
*/
|
||||
public static String getResourceStringFromJar(String resourcePath, Class<?> referenceClass) throws IOException {
|
||||
@@ -31,59 +34,34 @@ public class ResourceUtil {
|
||||
|
||||
/**
|
||||
* Reads a resource as a string from a specific jar file. See {@link #getResourceFromJar(String, Class)}.
|
||||
* @param resourcePath The resource to read
|
||||
*
|
||||
* @param resourcePath The resource to read
|
||||
* @param referenceClass The class, from whose jar to get the resource from
|
||||
* @param charset The charset to decode the raw bytes with
|
||||
* @param charset The charset to decode the raw bytes with
|
||||
*
|
||||
* @return The string from the resource
|
||||
*
|
||||
* @throws IOException From {@link #readBytes(InputStream)}
|
||||
*/
|
||||
public static String getResourceStringFromJar(String resourcePath, Class<?> referenceClass, Charset charset) throws IOException {
|
||||
public static String getResourceStringFromJar(String resourcePath, Class<?> referenceClass, Charset charset)
|
||||
throws IOException {
|
||||
return new String(getResourceBytesFromJar(resourcePath, referenceClass), charset);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a resource as a string, using the {@link StandardCharsets#UTF_8} charset.
|
||||
* @param resourcePath The resource to read
|
||||
* @return The string from the resource
|
||||
* @throws IOException From {@link #readBytes(InputStream)}
|
||||
*/
|
||||
public static String getResourceString(String resourcePath) throws IOException {
|
||||
return getResourceString(resourcePath, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a resource as a string.
|
||||
* @param resourcePath The resource to read
|
||||
* @param charset The charset to decode the raw bytes with
|
||||
* @return The string from the resource
|
||||
* @throws IOException From {@link #readBytes(InputStream)}
|
||||
*/
|
||||
public static String getResourceString(String resourcePath, Charset charset) throws IOException {
|
||||
return new String(getResourceBytes(resourcePath), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the raw bytes of a resource in a specific jar file. See {@link #getResourceFromJar(String, Class)}.
|
||||
* @param resourcePath The resource to read
|
||||
*
|
||||
* @param resourcePath The resource to read
|
||||
* @param referenceClass The class, from whose jar to get the resource from
|
||||
*
|
||||
* @return The bytes of the resource
|
||||
*
|
||||
* @throws IOException From {@link #readBytes(InputStream)}
|
||||
*/
|
||||
public static byte[] getResourceBytesFromJar(String resourcePath, Class<?> referenceClass) throws IOException {
|
||||
return readBytesSafe(getResourceFromJar(resourcePath, referenceClass), resourcePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the raw bytes of a resource.
|
||||
* @param resourcePath The resource to read
|
||||
* @return The bytes of the resource
|
||||
* @throws IOException From {@link #readBytes(InputStream)}
|
||||
*/
|
||||
public static byte[] getResourceBytes(String resourcePath) throws IOException {
|
||||
return readBytesSafe(ResourceUtil.class.getResourceAsStream(resourcePath), resourcePath);
|
||||
}
|
||||
|
||||
private static byte[] readBytesSafe(InputStream stream, String resourcePath) throws IOException {
|
||||
if (stream == null) {
|
||||
throw new FileNotFoundException("Could not find resource at " + resourcePath);
|
||||
@@ -91,10 +69,50 @@ public class ResourceUtil {
|
||||
return readBytes(stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a resource from the jar file of a specific class. Falls back to
|
||||
* {@link Class#getResourceAsStream(String)} if the resource is not found in the jar, or the class is not from a jar
|
||||
* file.
|
||||
*
|
||||
* @param resourcePath The resource to retrieve
|
||||
* @param referenceClass The class, from whose jar to get the resource from
|
||||
*
|
||||
* @return The resource, or null if it was not found.
|
||||
*/
|
||||
public static InputStream getResourceFromJar(String resourcePath, Class<?> referenceClass) {
|
||||
URL classFile = referenceClass.getResource('/' + referenceClass.getName().replace('.', '/') + ".class");
|
||||
lookup:
|
||||
{
|
||||
if (classFile == null) {
|
||||
break lookup;
|
||||
}
|
||||
String file = classFile.getFile();
|
||||
int id = file.indexOf("!");
|
||||
if (!classFile.getProtocol().equals("jar") || id < 0) {
|
||||
break lookup;
|
||||
}
|
||||
//Loading from a jar
|
||||
try {
|
||||
URL resource = new URL("jar:" + file.substring(0, id) + "!" + resourcePath);
|
||||
return resource.openStream();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Failed to load resource " + resourcePath + " from jar " + file.substring(0, id));
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
//Fallback logic
|
||||
System.out.println("Using fallback resource loading logic for " + resourcePath + " with reference to " +
|
||||
referenceClass.getName());
|
||||
return referenceClass.getResourceAsStream(resourcePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully reads a stream into a byte array.
|
||||
*
|
||||
* @param stream The stream to read
|
||||
*
|
||||
* @return The data from the stream
|
||||
*
|
||||
* @throws IOException From {@link InputStream#read(byte[])}
|
||||
*/
|
||||
public static byte[] readBytes(InputStream stream) throws IOException {
|
||||
@@ -108,34 +126,42 @@ public class ResourceUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a resource from the jar file of a specific class.
|
||||
* Falls back to {@link Class#getResourceAsStream(String)} if the resource is not found in the jar, or the class is
|
||||
* not from a jar file.
|
||||
* @param resourcePath The resource to retrieve
|
||||
* @param referenceClass The class, from whose jar to get the resource from
|
||||
* @return The resource, or null if it was not found.
|
||||
* Reads a resource as a string, using the {@link StandardCharsets#UTF_8} charset.
|
||||
*
|
||||
* @param resourcePath The resource to read
|
||||
*
|
||||
* @return The string from the resource
|
||||
*
|
||||
* @throws IOException From {@link #readBytes(InputStream)}
|
||||
*/
|
||||
public static InputStream getResourceFromJar(String resourcePath, Class<?> referenceClass) {
|
||||
URL classFile = referenceClass.getResource('/' + referenceClass.getName().replace('.', '/') + ".class");
|
||||
lookup:
|
||||
{
|
||||
if (classFile == null)
|
||||
break lookup;
|
||||
String file = classFile.getFile();
|
||||
int id = file.indexOf("!");
|
||||
if (!classFile.getProtocol().equals("jar") || id < 0)
|
||||
break lookup;
|
||||
//Loading from a jar
|
||||
try {
|
||||
URL resource = new URL("jar:" + file.substring(0, id) + "!" + resourcePath);
|
||||
return resource.openStream();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Failed to load resource " + resourcePath + " from jar " + file.substring(0, id));
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
//Fallback logic
|
||||
System.out.println("Using fallback resource loading logic for " + resourcePath + " with reference to " + referenceClass.getName());
|
||||
return referenceClass.getResourceAsStream(resourcePath);
|
||||
public static String getResourceString(String resourcePath) throws IOException {
|
||||
return getResourceString(resourcePath, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a resource as a string.
|
||||
*
|
||||
* @param resourcePath The resource to read
|
||||
* @param charset The charset to decode the raw bytes with
|
||||
*
|
||||
* @return The string from the resource
|
||||
*
|
||||
* @throws IOException From {@link #readBytes(InputStream)}
|
||||
*/
|
||||
public static String getResourceString(String resourcePath, Charset charset) throws IOException {
|
||||
return new String(getResourceBytes(resourcePath), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the raw bytes of a resource.
|
||||
*
|
||||
* @param resourcePath The resource to read
|
||||
*
|
||||
* @return The bytes of the resource
|
||||
*
|
||||
* @throws IOException From {@link #readBytes(InputStream)}
|
||||
*/
|
||||
public static byte[] getResourceBytes(String resourcePath) throws IOException {
|
||||
return readBytesSafe(ResourceUtil.class.getResourceAsStream(resourcePath), resourcePath);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user