reformat code

This commit is contained in:
FalsePattern committed 2022-06-08 16:01:06 +02:00
1 parent c4248f7100
commit 025b47669f
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);
}
}