aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/moe/nea/caelo
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-03-30 19:44:32 +0100
committerLinnea Gräf <nea@nea.moe>2024-03-30 19:44:32 +0100
commit0414b87e02e51b51cf9ef0c165e5ed61e5193160 (patch)
tree0d1a0144c44b252dcabc2c1d685a7d2b27e6adee /src/main/java/moe/nea/caelo
downloadveloxcaelo-0414b87e02e51b51cf9ef0c165e5ed61e5193160.tar.gz
veloxcaelo-0414b87e02e51b51cf9ef0c165e5ed61e5193160.tar.bz2
veloxcaelo-0414b87e02e51b51cf9ef0c165e5ed61e5193160.zip
Initial commit
Diffstat (limited to 'src/main/java/moe/nea/caelo')
-rw-r--r--src/main/java/moe/nea/caelo/Caelo.kt44
-rw-r--r--src/main/java/moe/nea/caelo/CaeloCommand.kt54
-rw-r--r--src/main/java/moe/nea/caelo/event/NeaTickEvent.kt7
-rw-r--r--src/main/java/moe/nea/caelo/init/MixinPlugin.java47
-rw-r--r--src/main/java/moe/nea/caelo/mixin/PatchCustomItemModelCache.java42
-rw-r--r--src/main/java/moe/nea/caelo/optifine/OptifineCustomItemCache.kt78
-rw-r--r--src/main/java/moe/nea/caelo/util/Histogram.kt17
-rw-r--r--src/main/java/moe/nea/caelo/util/InterModUtil.kt8
-rw-r--r--src/main/java/moe/nea/caelo/util/MC.kt13
9 files changed, 310 insertions, 0 deletions
diff --git a/src/main/java/moe/nea/caelo/Caelo.kt b/src/main/java/moe/nea/caelo/Caelo.kt
new file mode 100644
index 0000000..76e56bf
--- /dev/null
+++ b/src/main/java/moe/nea/caelo/Caelo.kt
@@ -0,0 +1,44 @@
+package moe.nea.caelo
+
+import moe.nea.caelo.event.NeaTickEvent
+import moe.nea.caelo.init.MixinPlugin
+import moe.nea.caelo.optifine.OptifineCustomItemCache
+import moe.nea.caelo.util.InterModUtil
+import moe.nea.caelo.util.MC
+import net.minecraft.client.Minecraft
+import net.minecraftforge.client.ClientCommandHandler
+import net.minecraftforge.common.MinecraftForge
+import net.minecraftforge.fml.common.Mod
+import net.minecraftforge.fml.common.event.FMLInitializationEvent
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.minecraftforge.fml.common.gameevent.TickEvent
+import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent
+
+@Mod(modid = "veloxcaelo", useMetadata = true)
+class Caelo {
+ @SubscribeEvent
+ fun onTick(tick: ClientTickEvent) {
+ if (tick.phase != TickEvent.Phase.END)
+ return
+ if (Minecraft.getMinecraft().thePlayer == null)
+ return
+ MinecraftForge.EVENT_BUS.post(NeaTickEvent(tickCount++))
+ }
+
+ var tickCount = 0
+
+ @Mod.EventHandler
+ fun onInit(event: FMLInitializationEvent) {
+ if (InterModUtil.isOptifineLoaded) {
+ MinecraftForge.EVENT_BUS.register(OptifineCustomItemCache)
+ }
+ MinecraftForge.EVENT_BUS.register(this)
+ ClientCommandHandler.instance.registerCommand(CaeloCommand)
+ CaeloCommand.subcommand("mixins") { args ->
+ MC.display("Injected mixins:")
+ MixinPlugin.loadedMixinClasses.forEach {
+ MC.display(" - $it")
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/moe/nea/caelo/CaeloCommand.kt b/src/main/java/moe/nea/caelo/CaeloCommand.kt
new file mode 100644
index 0000000..b5a1688
--- /dev/null
+++ b/src/main/java/moe/nea/caelo/CaeloCommand.kt
@@ -0,0 +1,54 @@
+package moe.nea.caelo
+
+import moe.nea.caelo.util.MC
+import net.minecraft.command.CommandBase
+import net.minecraft.command.ICommandSender
+import net.minecraft.util.BlockPos
+
+object CaeloCommand : CommandBase() {
+ override fun getCommandName(): String {
+ return "veloxcaelo"
+ }
+
+ override fun getCommandAliases(): List<String> {
+ return listOf("velox")
+ }
+
+ override fun canCommandSenderUseCommand(sender: ICommandSender?): Boolean {
+ return true
+ }
+
+ override fun getCommandUsage(sender: ICommandSender?): String {
+ return ""
+ }
+
+ override fun addTabCompletionOptions(
+ sender: ICommandSender?,
+ args: Array<out String>,
+ pos: BlockPos?
+ ): List<String> {
+ if (args.size == 1) {
+ return getListOfStringsMatchingLastWord(args, subcommands.keys)
+ }
+ return emptyList()
+ }
+
+ private val subcommands = mutableMapOf<String, (args: Array<String>) -> Unit>()
+
+ fun subcommand(name: String, function: (args: Array<String>) -> Unit) {
+ subcommands[name] = function
+ }
+
+ override fun processCommand(iCommandSender: ICommandSender?, args: Array<String>) {
+ if (args.isEmpty()) {
+ MC.display("§cMissing subcommand. Check the tab completions.")
+ return
+ }
+ val subCommand = subcommands[args[0]]
+ if (subCommand == null) {
+ MC.display("§cInvalid subcommand. Check the tab completions.")
+ return
+ }
+ subCommand.invoke(args)
+ }
+} \ No newline at end of file
diff --git a/src/main/java/moe/nea/caelo/event/NeaTickEvent.kt b/src/main/java/moe/nea/caelo/event/NeaTickEvent.kt
new file mode 100644
index 0000000..6121203
--- /dev/null
+++ b/src/main/java/moe/nea/caelo/event/NeaTickEvent.kt
@@ -0,0 +1,7 @@
+package moe.nea.caelo.event
+
+import net.minecraftforge.fml.common.eventhandler.Event
+
+data class NeaTickEvent(
+ val tickCounter: Int,
+) : Event() \ No newline at end of file
diff --git a/src/main/java/moe/nea/caelo/init/MixinPlugin.java b/src/main/java/moe/nea/caelo/init/MixinPlugin.java
new file mode 100644
index 0000000..fafc55d
--- /dev/null
+++ b/src/main/java/moe/nea/caelo/init/MixinPlugin.java
@@ -0,0 +1,47 @@
+package moe.nea.caelo.init;
+
+import org.spongepowered.asm.lib.tree.ClassNode;
+import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
+import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class MixinPlugin implements IMixinConfigPlugin {
+ @Override
+ public void onLoad(String mixinPackage) {
+ }
+
+ @Override
+ public String getRefMapperConfig() {
+ return null;
+ }
+
+ @Override
+ public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
+ return true;
+ }
+
+ @Override
+ public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
+
+ }
+
+ @Override
+ public List<String> getMixins() {
+ return null;
+ }
+
+ @Override
+ public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
+
+ }
+
+ public static Set<String> loadedMixinClasses = new HashSet<>();
+
+ @Override
+ public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
+ loadedMixinClasses.add(mixinClassName);
+ }
+}
diff --git a/src/main/java/moe/nea/caelo/mixin/PatchCustomItemModelCache.java b/src/main/java/moe/nea/caelo/mixin/PatchCustomItemModelCache.java
new file mode 100644
index 0000000..afeafef
--- /dev/null
+++ b/src/main/java/moe/nea/caelo/mixin/PatchCustomItemModelCache.java
@@ -0,0 +1,42 @@
+package moe.nea.caelo.mixin;
+
+import moe.nea.caelo.optifine.OptifineCustomItemCache;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.optifine.CustomItemProperties;
+import net.optifine.CustomItems;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Pseudo;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+
+@Pseudo
+@Mixin(value = CustomItems.class, remap = false)
+public class PatchCustomItemModelCache {
+
+ @SuppressWarnings("InvalidInjectorMethodSignature")
+ @Inject(method = "getCustomItemProperties", at = @At("HEAD"), cancellable = true)
+ private static void overrideCustomItemProperties(
+ ItemStack itemStack, int type,
+ CallbackInfoReturnable<CustomItemProperties> cir) {
+ OptifineCustomItemCache.retrieveCacheHit(itemStack, type, cir);
+ }
+
+ @Inject(method = "getCustomItemProperties", at = @At(value = "RETURN", ordinal = 2),
+ locals = LocalCapture.CAPTURE_FAILHARD)
+ private static void storeCustomItemProperties(
+ ItemStack itemStack, int type, CallbackInfoReturnable<CustomItemProperties> cir,
+ Item item, int itemId, CustomItemProperties[] cips, int i, CustomItemProperties cip) {
+ OptifineCustomItemCache.storeCustomItemProperties(itemStack, type, cip);
+ }
+
+ @Inject(method = "getCustomItemProperties", at = @At(value = "RETURN", ordinal = 3))
+ private static void storeCustomItemProperties(
+ ItemStack itemStack, int type, CallbackInfoReturnable<CustomItemProperties> cir) {
+ OptifineCustomItemCache.storeNoCustomItemProperties(itemStack, type);
+ }
+
+
+} \ No newline at end of file
diff --git a/src/main/java/moe/nea/caelo/optifine/OptifineCustomItemCache.kt b/src/main/java/moe/nea/caelo/optifine/OptifineCustomItemCache.kt
new file mode 100644
index 0000000..0bd6d78
--- /dev/null
+++ b/src/main/java/moe/nea/caelo/optifine/OptifineCustomItemCache.kt
@@ -0,0 +1,78 @@
+package moe.nea.caelo.optifine
+
+import moe.nea.caelo.CaeloCommand
+import moe.nea.caelo.event.NeaTickEvent
+import moe.nea.caelo.util.Histogram
+import moe.nea.caelo.util.MC
+import net.minecraft.item.ItemStack
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.optifine.CustomItemProperties
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
+
+object OptifineCustomItemCache {
+
+ init {
+ CaeloCommand.subcommand("opticache") { args ->
+ val cache = cacheSizeHistory.lastOrNull() ?: CacheStats()
+ MC.display("OptiCache stats:")
+ MC.display("- History: §3${cacheSizeHistory.size}")
+ MC.display("- Misses: §c${cache.cacheMisses}")
+ MC.display("- Hits: §a${cache.cacheHits}")
+ MC.display("- Entries: §b${cache.uniquePropertyBearingStacks}")
+ }
+ }
+
+ class CacheKey(val itemStack: ItemStack, val type: Int) {
+ override fun equals(other: Any?): Boolean {
+ if (other !is CacheKey) return false
+ return itemStack === other.itemStack && type == other.type
+ }
+
+ override fun hashCode(): Int {
+ return System.identityHashCode(itemStack) + type * 31
+ }
+ }
+
+ data class CacheStats(
+ var cacheHits: Int = 0,
+ var cacheMisses: Int = 0,
+ var uniquePropertyBearingStacks: Int = 0,
+ )
+
+ private val map = mutableMapOf<CacheKey, CustomItemProperties?>()
+ private val cacheSizeHistory = Histogram<CacheStats>(1000)
+ private var cacheStats = CacheStats()
+
+ @SubscribeEvent
+ fun onTick(event: NeaTickEvent) {
+ cacheSizeHistory.append(cacheStats)
+ cacheStats = CacheStats()
+ map.clear()
+ }
+
+ @JvmStatic
+ fun retrieveCacheHit(
+ itemStack: ItemStack,
+ type: Int,
+ cir: CallbackInfoReturnable<CustomItemProperties?>
+ ) {
+ val key = CacheKey(itemStack, type)
+ if (!map.containsKey(key)) {
+ cacheStats.cacheMisses++
+ return
+ }
+ cacheStats.cacheHits++
+ cir.returnValue = map[key]
+ }
+
+ @JvmStatic
+ fun storeCustomItemProperties(itemStack: ItemStack, type: Int, cip: CustomItemProperties) {
+ map[CacheKey(itemStack, type)] = cip
+ cacheStats.uniquePropertyBearingStacks++
+ }
+
+ @JvmStatic
+ fun storeNoCustomItemProperties(itemStack: ItemStack, type: Int) {
+ map[CacheKey(itemStack, type)] = null
+ }
+} \ No newline at end of file
diff --git a/src/main/java/moe/nea/caelo/util/Histogram.kt b/src/main/java/moe/nea/caelo/util/Histogram.kt
new file mode 100644
index 0000000..6c4add1
--- /dev/null
+++ b/src/main/java/moe/nea/caelo/util/Histogram.kt
@@ -0,0 +1,17 @@
+package moe.nea.caelo.util
+
+class Histogram<T>(val maxSize: Int) : Iterable<T> {
+ private val dequeue = ArrayDeque<T>()
+ fun append(element: T) {
+ dequeue.addLast(element)
+ if (dequeue.size > maxSize) {
+ dequeue.removeFirst()
+ }
+ }
+
+ val size get() = dequeue.size
+
+ override fun iterator(): Iterator<T> {
+ return dequeue.iterator()
+ }
+} \ No newline at end of file
diff --git a/src/main/java/moe/nea/caelo/util/InterModUtil.kt b/src/main/java/moe/nea/caelo/util/InterModUtil.kt
new file mode 100644
index 0000000..d7b4e90
--- /dev/null
+++ b/src/main/java/moe/nea/caelo/util/InterModUtil.kt
@@ -0,0 +1,8 @@
+package moe.nea.caelo.util
+
+import net.minecraftforge.fml.client.FMLClientHandler
+
+object InterModUtil {
+ val isOptifineLoaded get() = FMLClientHandler.instance().hasOptifine()
+
+}
diff --git a/src/main/java/moe/nea/caelo/util/MC.kt b/src/main/java/moe/nea/caelo/util/MC.kt
new file mode 100644
index 0000000..f05c217
--- /dev/null
+++ b/src/main/java/moe/nea/caelo/util/MC.kt
@@ -0,0 +1,13 @@
+package moe.nea.caelo.util
+
+import net.minecraft.client.Minecraft
+import net.minecraft.client.entity.EntityPlayerSP
+import net.minecraft.util.ChatComponentText
+
+object MC {
+ fun display(text: String) {
+ player?.addChatMessage(ChatComponentText("§b[Velox] §f$text"))
+ }
+
+ val player: EntityPlayerSP? get() = Minecraft.getMinecraft().thePlayer
+} \ No newline at end of file