Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package moddedmite.rustedironcore.internal.client.chat;

import net.minecraft.Minecraft;

/** Colour of the {@code §x} RGB code currently active in {@code FontRenderer.renderStringAtPos}. */
public interface RgbTextColor {
/** The active RGB colour, -1 when a legacy colour (or none) is active. */
int ric$activeRgbColor();

/**
* {@code rgb} as the RGBA colour {@code renderStringAtPos} sets for a legacy colour code: anaglyph-adjusted and, for the shadow
* pass, darkened the way MITE darkens its own codes.
*/
static float[] toTextColor(int rgb, boolean shadow, float alpha) {
int r = rgb >> 16 & 255;
int g = rgb >> 8 & 255;
int b = rgb & 255;
if (Minecraft.theMinecraft.gameSettings.anaglyph) {
int luminance = (r * 30 + g * 59 + b * 11) / 100;
g = (r * 30 + g * 70) / 100;
b = (r * 30 + b * 70) / 100;
r = luminance;
}
if (shadow) {
r /= 4;
g /= 4;
b /= 4;
}
return new float[]{r / 255.0F, g / 255.0F, b / 255.0F, alpha};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package moddedmite.rustedironcore.internal.client.texture;

import net.minecraft.AnimationMetadataSection;

/** A {@code TextureAtlasSprite} that blends animation frames when its metadata asks for {@code interpolate}. */
public interface InterpolatedSprite {
/** Called after the sprite was loaded with {@code sourceMetadata} (the "animation" section of its resource, or null). */
void rustedIronCore$retainInterpolation(AnimationMetadataSection sourceMetadata);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package moddedmite.rustedironcore.internal.client.texture;

import moddedmite.rustedironcore.api.resource.LegacyTextureResources;
import net.minecraft.Resource;
import net.minecraft.ResourceLocation;
import net.minecraft.ResourceManager;

import java.io.IOException;
import java.util.List;
import java.util.Set;

/** A resource manager whose {@link #getResource} resolves legacy atlas names like {@link LegacyTextureResources#getResource}. */
public final class LegacyAliasResourceManager implements ResourceManager {
private final ResourceManager delegate;

public LegacyAliasResourceManager(ResourceManager delegate) {
this.delegate = delegate;
}

@Override
public Set getResourceDomains() {
return this.delegate.getResourceDomains();
}

@Override
public Resource getResource(ResourceLocation location) {
try {
return LegacyTextureResources.getResource(this.delegate, location);
} catch (IOException e) {
throw LegacyAliasResourceManager.<RuntimeException>sneakyThrow(e);
}
}

@Override
public List getAllResources(ResourceLocation location) {
return this.delegate.getAllResources(location);
}

/** MITE's {@code getResource} throws {@link IOException} without declaring it; callers catch it, so it is passed on unchanged. */
@SuppressWarnings("unchecked")
private static <T extends Throwable> T sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package moddedmite.rustedironcore.internal.compat;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* Detects which FishModLoader runs RIC.
* <p>
* FML 3.x renders through OpenGL, so RIC's render mixins target the original MITE method bodies (the legacy route).
* FML 4.x with the Vulkan backend rewrites most render methods for its native renderer, one switchable "area" at a time
* ({@code fml.vulkan.native}, {@code fml.vulkan.native.off}); RIC mixins on such methods take the native route instead.
* An area whose native renderer is switched off runs MITE's code again and therefore uses the legacy route.
*/
public final class FmlRuntime {
public enum Route {
LEGACY, NATIVE
}

private static final Logger LOGGER = LogManager.getLogger("RustedIronCore");
private static final String FML_CLASS = "net.xiaoyu233.fml.FishModLoader";
private static final String VULKAN_BACKEND_CLASS = "net.xiaoyu233.fml.vulkan.VulkanBackend";
private static final String VULKAN_CONFIG_CLASS = "net.xiaoyu233.fml.vulkan.VulkanConfig";

private static final String VERSION = readVersion();
private static final boolean VULKAN = majorVersion(VERSION) >= 4 && classPresent(VULKAN_BACKEND_CLASS);
private static final Map<String, Boolean> NATIVE_AREAS = new ConcurrentHashMap<>();

static {
LOGGER.info("FishModLoader {} detected, {} render route", VERSION, VULKAN ? "Vulkan (per native area)" : "legacy OpenGL");
}

private FmlRuntime() {
}

/** Version of the running FishModLoader, "unknown" if it cannot be read. */
public static String fmlVersion() {
return VERSION;
}

/** True on FishModLoader 4.x with the Vulkan backend. */
public static boolean isVulkan() {
return VULKAN;
}

/** True when FML's native renderer owns the methods of {@code area} (names of {@code fishmodloader.native.<area>.mixins.json}). */
public static boolean isNativeArea(String area) {
return VULKAN && NATIVE_AREAS.computeIfAbsent(area, FmlRuntime::queryNativeArea);
}

public static Route route(String area) {
return isNativeArea(area) ? Route.NATIVE : Route.LEGACY;
}

private static boolean queryNativeArea(String area) {
boolean active;
try {
active = (Boolean) Class.forName(VULKAN_CONFIG_CLASS).getMethod("areaActive", String.class).invoke(null, area);
} catch (ReflectiveOperationException | LinkageError | ClassCastException e) {
// the native renderer is on by default in FML 4.x
LOGGER.warn("Cannot query FML native area '{}', assuming it is active: {}", area, e.toString());
active = true;
}
LOGGER.info("FML native area '{}': {} route", area, active ? "native" : "legacy");
return active;
}

private static String readVersion() {
// Reflection on purpose: FishModLoader.VERSION is a compile-time constant and would be inlined as the version RIC was built against
try {
return String.valueOf(Class.forName(FML_CLASS).getField("VERSION").get(null));
} catch (ReflectiveOperationException | LinkageError e) {
LOGGER.warn("Cannot read the FishModLoader version, using the legacy render route: {}", e.toString());
return "unknown";
}
}

static int majorVersion(String version) {
int end = 0;
while (end < version.length() && Character.isDigit(version.charAt(end))) {
end++;
}
return end == 0 ? -1 : Integer.parseInt(version.substring(0, end));
}

private static boolean classPresent(String name) {
try {
Class.forName(name, false, FmlRuntime.class.getClassLoader());
return true;
} catch (ClassNotFoundException | LinkageError e) {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package moddedmite.rustedironcore.internal.compat;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

/**
* GL11-shaped state calls into FML 4.x's native renderer ({@code net.xiaoyu233.fml.vulkan.render.state.GlShim}), for RIC code on
* the native route. RIC is built against FML 3.x, so the class is bound at runtime.
* Only called on the native route, render thread only (like the shim itself).
*/
public final class NativeGlShim {
private static final String GL_SHIM_CLASS = "net.xiaoyu233.fml.vulkan.render.state.GlShim";

private static final MethodHandle ENABLE;
private static final MethodHandle DISABLE;
private static final MethodHandle BLEND_FUNC;
private static final MethodHandle COLOR4F;
private static final MethodHandle LINE_WIDTH;
private static final MethodHandle DEPTH_MASK;

static {
MethodHandle enable = null, disable = null, blendFunc = null, color4f = null, lineWidth = null, depthMask = null;
if (FmlRuntime.isVulkan()) {
try {
Class<?> shim = Class.forName(GL_SHIM_CLASS);
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
enable = lookup.findStatic(shim, "enable", MethodType.methodType(void.class, int.class));
disable = lookup.findStatic(shim, "disable", MethodType.methodType(void.class, int.class));
blendFunc = lookup.findStatic(shim, "blendFunc", MethodType.methodType(void.class, int.class, int.class));
color4f = lookup.findStatic(shim, "color4f", MethodType.methodType(void.class, float.class, float.class, float.class, float.class));
lineWidth = lookup.findStatic(shim, "lineWidth", MethodType.methodType(void.class, float.class));
depthMask = lookup.findStatic(shim, "depthMask", MethodType.methodType(void.class, boolean.class));
} catch (ReflectiveOperationException | LinkageError e) {
enable = null;
}
}
ENABLE = enable;
DISABLE = disable;
BLEND_FUNC = blendFunc;
COLOR4F = color4f;
LINE_WIDTH = lineWidth;
DEPTH_MASK = depthMask;
}

private NativeGlShim() {
}

public static void enable(int cap) {
try {
ENABLE.invokeExact(cap);
} catch (Throwable t) {
throw rethrow(t);
}
}

public static void disable(int cap) {
try {
DISABLE.invokeExact(cap);
} catch (Throwable t) {
throw rethrow(t);
}
}

public static void blendFunc(int src, int dst) {
try {
BLEND_FUNC.invokeExact(src, dst);
} catch (Throwable t) {
throw rethrow(t);
}
}

public static void color4f(float r, float g, float b, float a) {
try {
COLOR4F.invokeExact(r, g, b, a);
} catch (Throwable t) {
throw rethrow(t);
}
}

public static void lineWidth(float width) {
try {
LINE_WIDTH.invokeExact(width);
} catch (Throwable t) {
throw rethrow(t);
}
}

public static void depthMask(boolean flag) {
try {
DEPTH_MASK.invokeExact(flag);
} catch (Throwable t) {
throw rethrow(t);
}
}

private static RuntimeException rethrow(Throwable t) {
if (t instanceof RuntimeException runtime) throw runtime;
if (t instanceof Error error) throw error;
throw new IllegalStateException(t);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package moddedmite.rustedironcore.internal.config;

import java.util.List;

import static moddedmite.rustedironcore.internal.compat.FmlRuntime.Route.LEGACY;

/** Plugin of {@code glacier.mixins.json}. */
public class GlacierMixinConfig extends RoutedMixinPlugin {
public GlacierMixinConfig() {
super(List.of(new Routed("client.gui.GuiContainerCreativeMixin", "container", LEGACY)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package moddedmite.rustedironcore.internal.config;

import java.util.List;

import static moddedmite.rustedironcore.internal.compat.FmlRuntime.Route.NATIVE;

/** Plugin of {@code glacier.vulkan.mixins.json}: overwrites that must merge before FML 4.x's native redirects. */
public class GlacierVulkanMixinConfig extends RoutedMixinPlugin {
public GlacierVulkanMixinConfig() {
super(List.of(new Routed("client.gui.GuiContainerCreativeMixin", "container", NATIVE)));
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
package moddedmite.rustedironcore.internal.config;

import moddedmite.rustedironcore.api.util.Platform;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;

import java.util.List;
import java.util.Set;

public class MixinConfig implements IMixinConfigPlugin {
@Override
public void onLoad(String s) {

}

@Override
public String getRefMapperConfig() {
return null;
import static moddedmite.rustedironcore.internal.compat.FmlRuntime.Route.LEGACY;
import static moddedmite.rustedironcore.internal.compat.FmlRuntime.Route.NATIVE;

public class MixinConfig extends RoutedMixinPlugin {
public MixinConfig() {
super(List.of(
new Routed("client.render.RenderBipedMixin", "special", LEGACY),
new Routed("client.render.RenderPlayerMixin", "special", LEGACY),
new Routed("client.FontRendererColorMixin", "text", LEGACY),
new Routed("client.vulkan.FontRendererVulkanMixin", "text", NATIVE),
new Routed("client.render.RenderGlobalMixin", "sky", LEGACY),
new Routed("client.vulkan.RenderGlobalVulkanMixin", "sky", NATIVE),
new Routed("client.render.TextureMapAtlasMixin", "texture", LEGACY),
new Routed("client.vulkan.TextureMapVulkanMixin", "texture", NATIVE),
new Routed("client.vulkan.TextureAtlasSpriteVulkanMixin", "texture", NATIVE)));
}

@Override
Expand All @@ -32,24 +34,4 @@ public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
}
return true;
}

@Override
public void acceptTargets(Set<String> set, Set<String> set1) {

}

@Override
public List<String> getMixins() {
return null;
}

@Override
public void preApply(String s, ClassNode classNode, String s1, IMixinInfo iMixinInfo) {

}

@Override
public void postApply(String s, ClassNode classNode, String s1, IMixinInfo iMixinInfo) {

}
}
Loading
Loading