diff --git a/build.gradle.kts b/build.gradle.kts index 5837df1..f73d7c9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,7 +12,7 @@ plugins { // Project properties group = "github.kasuminova.stellarcore" -version = "1.4.5" +version = "1.4.9" // Set the toolchain version to decouple the Java we run Gradle with from the Java used to compile and run the mod java { @@ -148,6 +148,9 @@ repositories { maven { url = uri("https://maven.blamejared.com/") } + maven { + url = uri("https://maven.tterrag.com") // AutoSave, AutoConfig + } maven { url = uri("https://repo.spongepowered.org/maven") } @@ -206,7 +209,7 @@ dependencies { implementation(rfg.deobf("curse.maven:ae2-extended-life-570458:5147702")) compileOnly(rfg.deobf("curse.maven:CodeChickenLib-242818:2779848")) compileOnly(rfg.deobf("curse.maven:nuclearcraft-overhauled-336895:3862197")) - compileOnly(rfg.deobf("curse.maven:industrialcraft-2-242638:3838713")) + implementation(rfg.deobf("curse.maven:industrialcraft-2-242638:3838713")) compileOnly(rfg.deobf("curse.maven:mekanism-ce-unofficial-840735:5130458")) // compileOnly(rfg.deobf("curse.maven:mekanism-unofficial-edition-v10-edition-840735:4464199")) compileOnly(rfg.deobf("curse.maven:RedstoneFlux-270789:2920436")) @@ -231,6 +234,8 @@ dependencies { compileOnly(rfg.deobf("curse.maven:rgb-chat-702720:4092100")) compileOnly(rfg.deobf("curse.maven:endercore-231868:4671384")) compileOnly(rfg.deobf("curse.maven:ender-io-64578:4674244")) + compileOnly("info.loenwind.autosave:AutoSave:1.12.2:1.0.11") // EnderIO Dependency + compileOnly("info.loenwind.autoconfig:AutoConfig:1.12.2:1.0.2") // EnderIO Dependency compileOnly(rfg.deobf("curse.maven:tinkers-evolution-384589:4941753")) compileOnly(rfg.deobf("curse.maven:ore-excavation-250898:2897369")) compileOnly(rfg.deobf("curse.maven:techguns-244201:2958103")) diff --git a/src/main/java/github/kasuminova/stellarcore/common/config/StellarCoreConfig.java b/src/main/java/github/kasuminova/stellarcore/common/config/StellarCoreConfig.java index 6c64535..803c259 100644 --- a/src/main/java/github/kasuminova/stellarcore/common/config/StellarCoreConfig.java +++ b/src/main/java/github/kasuminova/stellarcore/common/config/StellarCoreConfig.java @@ -578,6 +578,9 @@ public static class Performance { @Config.Name("InGameInfoXML") public final InGameInfoXML inGameInfoXML = new InGameInfoXML(); + @Config.Name("ImmersiveEngineering") + public final ImmersiveEngineering immersiveEngineering = new ImmersiveEngineering(); + @Config.Name("Mekanism") public final Mekanism mekanism = new Mekanism(); @@ -677,6 +680,11 @@ public static class Vanilla { @Config.Name("PropertyEnumHashCodeCache") public boolean propertyEnumHashCodeCache = true; + @Config.Comment("(Server Performance) Improving BlockStateContainer$BlockStateImplementation#hashCode Performance with hashCode cache.") + @Config.RequiresMcRestart + @Config.Name("BlockStateImplementationHashCodeCache") + public boolean blockStateImplementationHashCodeCache = true; + @Config.Comment("(Client/Server Performance | Experimental) Replaces the internal default ArrayList of NonNullList with an ObjectArrayList (may not work).") @Config.RequiresMcRestart @Config.Name("NonNullListImprovements") @@ -742,10 +750,11 @@ public static class Vanilla { @Config.RequiresMcRestart @Config.Comment({ "(Client Performance) Modify the data structure of ModelBlock's textures map to improve performance and reduce memory usage.", - "This feature requires CensoredASM mod." + "This feature requires CensoredASM mod.", + "Known to be incompatible with DynamicTrees." }) @Config.Name("ModelBlockStringCanonicalization") - public boolean modelBlockStringCanonicalization = true; + public boolean modelBlockStringCanonicalization = false; @Config.Comment({ "(Client Performance | Experimental) Deduplicate vertexData array to optimise memory usage.", @@ -1006,6 +1015,10 @@ public static class EnderIOConduits { @Config.Name("EnderLiquidConduitNetworkTankMap") public boolean enderLiquidConduitNetworkTankMap = true; + @Config.Comment("(Server Performance | Experimental) Rewriting the eio conduit energy network computation logic to improve performance using multithreading.") + @Config.Name("NetworkPowerManagerImprovements") + public boolean networkPowerManager = true; + } public static class FTBLib { @@ -1026,6 +1039,11 @@ public static class FTBQuests { public static class IndustrialCraft2 { + @Config.RequiresMcRestart + @Config.Comment("(Server Performance | Experimental) Rewriting the ic2 energy network computation logic to improve performance using multithreading.") + @Config.Name("EnergyCalculatorLegImprovements") + public boolean energyCalculatorLeg = true; + @Config.Comment("(Server Performance) Improved some data structures, slight performance improvements.") @Config.Name("GridDataImprovements") public boolean energyCalculatorLegGridData = true; @@ -1034,6 +1052,10 @@ public static class IndustrialCraft2 { @Config.Name("EnergyNetLocalImprovements") public boolean energyNetLocal = true; + @Config.Comment("(Server Performance) Improve EnergyNetLocal#getIoTile and EnergyNetLocal#getSubTile fetching speed to optimise performance to some extent.") + @Config.Name("GetIoAndSubTileEnergyNetLocalImprovements") + public boolean getIoAndSubTile = true; + @Config.Comment("(Server Performance) Improved some data structures, slight performance improvements.") @Config.Name("GridImprovements") public boolean grid = true; @@ -1067,6 +1089,17 @@ public static class InGameInfoXML { } + public static class ImmersiveEngineering { + + @Config.Comment({ + "(Server Performance) 阻止 IE 机械方块传输能量时触发完整的方块更新,这可能会改进性能。", + "但如果出现奇怪的方块状态请尝试关闭此选项." + }) + @Config.Name("EnergyTransferNoUpdate") + public boolean energyTransferNoUpdate = true; + + } + public static class Mekanism { @Config.Comment({ @@ -1166,6 +1199,9 @@ public static class Features { @Config.Name("EnderIOConduits") public final EnderIOConduits enderIOConduits = new EnderIOConduits(); + @Config.Name("FluxNetworks") + public final FluxNetworks fluxNetworks = new FluxNetworks(); + @Config.Name("IC2") public final IC2 ic2 = new IC2(); @@ -1257,6 +1293,14 @@ public static class EnderIOConduits { public boolean prevEnderLiquidConduitLogSpam = true; } + + public static class FluxNetworks { + + @Config.Comment("(Server) Make FluxNetworks to generate a random int uid for each network, instead of using the self-incrementing ID.") + @Config.Name("RandomNetworkUniqueID") + public boolean randomNetworkUniqueID = false; + + } public static class IC2 { diff --git a/src/main/java/github/kasuminova/stellarcore/common/util/BlockPos2IntMap.java b/src/main/java/github/kasuminova/stellarcore/common/util/BlockPos2IntMap.java new file mode 100644 index 0000000..b2b710d --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/common/util/BlockPos2IntMap.java @@ -0,0 +1,265 @@ +package github.kasuminova.stellarcore.common.util; + +import com.github.bsideup.jabel.Desugar; +import com.google.common.collect.Iterators; +import it.unimi.dsi.fastutil.ints.IntCollection; +import it.unimi.dsi.fastutil.longs.Long2IntMap; +import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.AbstractObjectSet; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import net.minecraft.util.math.BlockPos; + +import javax.annotation.Nonnull; +import java.util.Iterator; +import java.util.Map; + +@SuppressWarnings({"CloneableClassInSecureContext", "UnusedReturnValue"}) +public class BlockPos2IntMap implements Object2IntMap<BlockPos> { + + protected final Long2IntOpenHashMap internal = new Long2IntOpenHashMap(); + protected EntrySet entrySet = null; + protected KeySet keySet = null; + + @Nonnull + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public ObjectSet<Map.Entry<BlockPos, Integer>> entrySet() { + return (ObjectSet) (entrySet == null ? entrySet = new EntrySet() : entrySet); + } + + @Override + public ObjectSet<Object2IntMap.Entry<BlockPos>> object2IntEntrySet() { + return entrySet == null ? entrySet = new EntrySet() : entrySet; + } + + @Nonnull + @Override + public ObjectSet<BlockPos> keySet() { + return keySet == null ? keySet = new KeySet() : keySet; + } + + @Nonnull + @Override + public IntCollection values() { + return internal.values(); + } + + @Override + public boolean containsValue(final int value) { + return internal.containsValue(value); + } + + @Override + public int put(final BlockPos key, final int value) { + return internal.put(key.toLong(), value); + } + + @Override + public int getInt(final Object key) { + if (key instanceof BlockPos pos) { + return internal.get(pos.toLong()); + } + return defaultReturnValue(); + } + + @Override + public int removeInt(final Object key) { + if (key instanceof BlockPos pos) { + return internal.remove(pos.toLong()); + } + return defaultReturnValue(); + } + + @Override + public void defaultReturnValue(final int rv) { + internal.defaultReturnValue(rv); + } + + @Override + public int defaultReturnValue() { + return internal.defaultReturnValue(); + } + + @Override + public Integer put(final BlockPos key, final Integer value) { + return internal.put(key.toLong(), (int) value); + } + + @Override + public Integer get(final Object key) { + if (key instanceof BlockPos pos) { + return internal.get(pos.toLong()); + } + return 0; + } + + @Override + public boolean containsKey(final Object key) { + if (key instanceof BlockPos pos) { + return internal.containsKey(pos.toLong()); + } + return false; + } + + @Override + public boolean containsValue(final Object value) { + if (value instanceof Integer i) { + return internal.containsValue(i); + } + return false; + } + + @Override + public Integer remove(final Object key) { + if (key instanceof BlockPos pos) { + return internal.remove(pos.toLong()); + } + return 0; + } + + @Override + public void putAll(final Map<? extends BlockPos, ? extends Integer> map) { + map.forEach((key, v) -> internal.put(key.toLong(), (int) v)); + } + + public int addTo(final BlockPos pos, final int incr) { + return internal.addTo(pos.toLong(), incr); + } + + @Override + public int size() { + return internal.size(); + } + + @Override + public boolean isEmpty() { + return internal.isEmpty(); + } + + @Override + public void clear() { + internal.clear(); + } + + public class EntrySet extends AbstractObjectSet<Object2IntMap.Entry<BlockPos>> { + + @Override + public int size() { + return internal.size(); + } + + @Override + public void clear() { + internal.clear(); + } + + @Nonnull + @Override + public ObjectIterator<Object2IntMap.Entry<BlockPos>> iterator() { + Iterator<Entry> transformed = Iterators.transform(internal.long2IntEntrySet().iterator(), Entry::new); + return new EntryIterator(transformed); + } + + } + + @Desugar + private record KeyIterator(EntryIterator parent) implements ObjectIterator<BlockPos> { + + @Override + public int skip(final int n) { + return parent.skip(n); + } + + @Override + public boolean hasNext() { + return parent.hasNext(); + } + + @Override + public BlockPos next() { + return parent.next().getKey(); + } + + } + + @Desugar + private record EntryIterator(Iterator<Entry> transformed) implements ObjectIterator<Object2IntMap.Entry<BlockPos>> { + + @Override + public int skip(final int n) { + int skipped = 0; + int i = 0; + while (i < n && hasNext()) { + transformed.next(); + skipped++; + i++; + } + return skipped; + } + + @Override + public boolean hasNext() { + return transformed.hasNext(); + } + + @Override + public Object2IntMap.Entry<BlockPos> next() { + return transformed.next(); + } + + } + + public class KeySet extends AbstractObjectSet<BlockPos> { + + @Nonnull + @Override + @SuppressWarnings("RedundantCast") + public ObjectIterator<BlockPos> iterator() { + return new KeyIterator((EntryIterator) (Object) (entrySet().iterator())); + } + + @Override + public int size() { + return internal.size(); + } + + } + + @SuppressWarnings("deprecation") + public static class Entry implements Object2IntMap.Entry<BlockPos> { + + private final Long2IntMap.Entry parent; + + public Entry(Long2IntMap.Entry parent) { + this.parent = parent; + } + + @Override + public BlockPos getKey() { + return BlockPos.fromLong(parent.getLongKey()); + } + + @Override + public Integer getValue() { + return parent.getValue(); + } + + @Override + public int setValue(final int value) { + return parent.setValue(value); + } + + @Override + public int getIntValue() { + return parent.getValue(); + } + + @Override + public Integer setValue(final Integer value) { + return parent.setValue(value); + } + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/common/util/HashedItemStack.java b/src/main/java/github/kasuminova/stellarcore/common/util/HashedItemStack.java index 09e0452..b667095 100644 --- a/src/main/java/github/kasuminova/stellarcore/common/util/HashedItemStack.java +++ b/src/main/java/github/kasuminova/stellarcore/common/util/HashedItemStack.java @@ -11,7 +11,7 @@ import java.util.Objects; @Desugar -public record HashedItemStack(ItemStack stack, int stackHashCode, boolean hasTag) { +public record HashedItemStack(ItemStack stack, int stackHashCode, int damage, boolean hasTag) { public static HashedItemStack ofTag(final ItemStack stack) { ItemStack copied = stack.copy(); @@ -22,14 +22,15 @@ public static HashedItemStack ofTagUnsafe(final ItemStack stack) { NBTTagCompound tag = stack.getTagCompound(); boolean hasTag = tag != null && !tag.isEmpty(); int hash; + int damage = stack.isItemStackDamageable() ? stack.getItemDamage() : stack.getHasSubtypes() ? stack.getMetadata() : 0; if (hasTag) { hash = Objects.hash(stack.getItem(), - stack.isItemStackDamageable() ? stack.getItemDamage() : stack.getHasSubtypes() ? stack.getMetadata() : 0, tag); + damage, tag); } else { - hash = Objects.hash(stack.getItem(), - stack.isItemStackDamageable() ? stack.getItemDamage() : stack.getHasSubtypes() ? stack.getMetadata() : 0); + hash = Objects.hash(stack.getItem(), + damage); } - return new HashedItemStack(stack, hash, hasTag); + return new HashedItemStack(stack, hash, damage, hasTag); } public static HashedItemStack ofMeta(final ItemStack stack) { @@ -38,14 +39,16 @@ public static HashedItemStack ofMeta(final ItemStack stack) { } public static HashedItemStack ofMetaUnsafe(final ItemStack stack) { - return new HashedItemStack(stack, Objects.hash(stack.getItem(), stack.getMetadata()), false); + int metadata = stack.getMetadata(); + return new HashedItemStack(stack, Objects.hash(stack.getItem(), metadata), metadata, false); } public static String stackToString(final ItemStack stack) { String stackTagStr = null; String registryName = Objects.requireNonNull(stack.getItem().getRegistryName()).toString(); - if (stack.getTagCompound() != null) { - stackTagStr = stack.getTagCompound().toString(); + NBTTagCompound tag = stack.getTagCompound(); + if (tag != null && !tag.isEmpty()) { + stackTagStr = tag.toString(); } return strToBase64(registryName) + "_" + stack.getItemDamage() + (stackTagStr == null ? "" : "_" + strToBase64(stackTagStr)); } @@ -60,12 +63,12 @@ public boolean equals(final Object o) { if (hasTag && !hashedItemStack.hasTag) { return false; } - return stackEqualsNonNBT(stack, hashedItemStack.stack) && (!hasTag || ItemStack.areItemStackTagsEqual(stack, hashedItemStack.stack)); + return stackEqualsNonNBT(stack, hashedItemStack.stack, damage, hashedItemStack.damage) && (!hasTag || ItemStack.areItemStackTagsEqual(stack, hashedItemStack.stack)); } return false; } - public static boolean stackEqualsNonNBT(@Nonnull ItemStack stack, @Nonnull ItemStack other) { + public static boolean stackEqualsNonNBT(@Nonnull ItemStack stack, @Nonnull ItemStack other, final int stackDamage, final int otherDamage) { if (stack.isEmpty() && other.isEmpty()) { return true; } @@ -75,17 +78,17 @@ public static boolean stackEqualsNonNBT(@Nonnull ItemStack stack, @Nonnull ItemS Item sItem = stack.getItem(); Item oItem = other.getItem(); if (sItem.getHasSubtypes() || oItem.getHasSubtypes()) { - return sItem.equals(other.getItem()) && - (stack.getItemDamage() == other.getItemDamage() || - stack.getItemDamage() == OreDictionary.WILDCARD_VALUE || - other.getItemDamage() == OreDictionary.WILDCARD_VALUE); + return sItem == oItem && ( + stackDamage == otherDamage || + stackDamage == OreDictionary.WILDCARD_VALUE || + otherDamage == OreDictionary.WILDCARD_VALUE); } else { return sItem.equals(other.getItem()); } } public HashedItemStack copy() { - return new HashedItemStack(stack.copy(), stackHashCode, hasTag); + return new HashedItemStack(stack.copy(), stackHashCode, damage, hasTag); } @Override diff --git a/src/main/java/github/kasuminova/stellarcore/common/util/RandomUtils.java b/src/main/java/github/kasuminova/stellarcore/common/util/RandomUtils.java index bfcc8ef..3a14b48 100644 --- a/src/main/java/github/kasuminova/stellarcore/common/util/RandomUtils.java +++ b/src/main/java/github/kasuminova/stellarcore/common/util/RandomUtils.java @@ -8,6 +8,10 @@ public static int nextInt(int bound) { return ThreadLocalRandom.current().nextInt(bound); } + public static int nextInt() { + return ThreadLocalRandom.current().nextInt(); + } + public static float nextFloat() { return ThreadLocalRandom.current().nextFloat(); } diff --git a/src/main/java/github/kasuminova/stellarcore/common/world/ParallelRandomBlockTicker.java b/src/main/java/github/kasuminova/stellarcore/common/world/ParallelRandomBlockTicker.java index 5a85e49..0034fcc 100644 --- a/src/main/java/github/kasuminova/stellarcore/common/world/ParallelRandomBlockTicker.java +++ b/src/main/java/github/kasuminova/stellarcore/common/world/ParallelRandomBlockTicker.java @@ -45,7 +45,7 @@ public void execute(final World world, final Random rand, final Profiler profile this.currentRand = rand; this.profiler = profiler; - if (this.enqueuedChunks.size() * randomTickSpeed >= 500) { + if (this.enqueuedChunks.size() * randomTickSpeed >= 1000) { this.enqueuedChunks.entrySet().parallelStream().forEach(entry -> { Chunk chunk = entry.getKey(); for (final TickData tickData : entry.getValue()) { diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/StellarCoreEarlyMixinLoader.java b/src/main/java/github/kasuminova/stellarcore/mixin/StellarCoreEarlyMixinLoader.java index 280e8a0..3492c14 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/StellarCoreEarlyMixinLoader.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/StellarCoreEarlyMixinLoader.java @@ -21,6 +21,7 @@ public class StellarCoreEarlyMixinLoader implements IFMLLoadingPlugin { addMixinCFG("mixins.stellar_core_minecraft_bakedquad.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.bakedQuadVertexDataCanonicalization); addMixinCFG("mixins.stellar_core_minecraft_blockfaceuv.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.blockFaceUVsCanonicalization); addMixinCFG("mixins.stellar_core_minecraft_blockpart.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.blockPartDataStructure); + addMixinCFG("mixins.stellar_core_minecraft_blockstateimpl.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.blockStateImplementationHashCodeCache); addMixinCFG("mixins.stellar_core_minecraft_chunk.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.blockPos2ValueMap); addMixinCFG("mixins.stellar_core_minecraft_chunk_cache.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.chunkBlockStateCache); addMixinCFG("mixins.stellar_core_minecraft_classmultimap.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.classMultiMap); @@ -38,7 +39,7 @@ public class StellarCoreEarlyMixinLoader implements IFMLLoadingPlugin { addMixinCFG("mixins.stellar_core_minecraft_world_load.json", () -> StellarCoreConfig.FEATURES.vanilla.handleClientWorldLoad); addMixinCFG("mixins.stellar_core_minecraft_world_pos_judgement.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.worldBlockPosJudgement); addMixinCFG("mixins.stellar_core_minecraft_worldserver.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.worldServerGetPendingBlockUpdates); - addMixinCFG("mixins.stellar_core_minecraft_statemapperbase.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.stateMapperBase); + addMixinCFG("mixins.stellar_core_minecraft_statemapperbase.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.parallelModelLoader || StellarCoreConfig.PERFORMANCE.vanilla.stateMapperBase); addMixinCFG("mixins.stellar_core_minecraft_stitcher.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.stitcherCache); // addMixinCFG("mixins.stellar_core_minecraft_texturemap.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.parallelTextureMapLoad); addMixinCFG("mixins.stellar_core_minecraft_texture_load.json", () -> StellarCoreConfig.PERFORMANCE.vanilla.parallelTextureLoad); @@ -97,6 +98,7 @@ public void injectData(final Map<String, Object> data) { StellarLog.LOG.info("[StellarCore-MixinLoader] Mixin config {} is disabled by config or mod is not loaded.", config); return; } + StellarLog.LOG.info("[StellarCore-MixinLoader] Adding {} to mixin configuration.", config); Mixins.addConfiguration(config); }); } diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/StellarCoreLateMixinLoader.java b/src/main/java/github/kasuminova/stellarcore/mixin/StellarCoreLateMixinLoader.java index 1814d0d..eed91ab 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/StellarCoreLateMixinLoader.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/StellarCoreLateMixinLoader.java @@ -15,59 +15,61 @@ public class StellarCoreLateMixinLoader implements ILateMixinLoader { private static final Map<String, BooleanSupplier> MIXIN_CONFIGS = new LinkedHashMap<>(); static { - addModdedMixinCFG("mixins.stellar_core_advancedrocketry.json", "advancedrocketry"); - addModdedMixinCFG("mixins.stellar_core_ae.json", "appliedenergistics2"); - addModdedMixinCFG("mixins.stellar_core_ancientspellcraft.json", "ancientspellcraft"); - addModdedMixinCFG("mixins.stellar_core_armourers_workshop.json", "armourers_workshop"); - addModdedMixinCFG("mixins.stellar_core_astralsorcery.json", "astralsorcery"); - addModdedMixinCFG("mixins.stellar_core_avaritia.json", "avaritia"); - addModdedMixinCFG("mixins.stellar_core_avaritiaddons.json", "avaritiaddons"); - addModdedMixinCFG("mixins.stellar_core_betterchat.json", "betterchat"); - addModdedMixinCFG("mixins.stellar_core_biomesoplenty.json", "biomesoplenty"); - addModdedMixinCFG("mixins.stellar_core_bloodmagic.json", "bloodmagic"); - addModdedMixinCFG("mixins.stellar_core_botania.json", "botania"); - addModdedMixinCFG("mixins.stellar_core_cfm.json", "cfm", () -> StellarCoreConfig.BUG_FIXES.mrCrayfishFurniture.imageCache); - addModdedMixinCFG("mixins.stellar_core_chisel.json", "chisel"); - addModdedMixinCFG("mixins.stellar_core_cofhcore.json", "cofhcore"); - addModdedMixinCFG("mixins.stellar_core_ctm.json", "ctm", () -> StellarCoreConfig.PERFORMANCE.ctm.textureMetadataHandler); - addModdedMixinCFG("mixins.stellar_core_cucumber.json", "cucumber"); - addModdedMixinCFG("mixins.stellar_core_customloadingscreen.json", "customloadingscreen"); - addModdedMixinCFG("mixins.stellar_core_customstartinggear.json", "customstartinggear"); - addModdedMixinCFG("mixins.stellar_core_draconicevolution.json", "draconicevolution"); - addModdedMixinCFG("mixins.stellar_core_ebwizardry.json", "ebwizardry"); - addModdedMixinCFG("mixins.stellar_core_endercore.json", "endercore"); - addModdedMixinCFG("mixins.stellar_core_enderio.json", "enderio"); - addModdedMixinCFG("mixins.stellar_core_enderioconduits.json", "enderio", "enderioconduits"); - addModdedMixinCFG("mixins.stellar_core_enderutilities.json", "enderutilities"); - addModdedMixinCFG("mixins.stellar_core_extrabotany.json", "extrabotany"); - addModdedMixinCFG("mixins.stellar_core_fluxnetworks.json", "fluxnetworks"); - addModdedMixinCFG("mixins.stellar_core_ftblib.json", "ftblib"); - addModdedMixinCFG("mixins.stellar_core_ftbquests.json", "ftbquests"); - addModdedMixinCFG("mixins.stellar_core_guguutils.json", "gugu-utils"); - addModdedMixinCFG("mixins.stellar_core_ic2.json", "ic2"); - addModdedMixinCFG("mixins.stellar_core_igi.json", "ingameinfoxml"); - addModdedMixinCFG("mixins.stellar_core_immersiveengineering.json", "immersiveengineering"); - addModdedMixinCFG("mixins.stellar_core_jei.json", "jei", () -> StellarCoreConfig.PERFORMANCE.vanilla.stitcherCache); - addModdedMixinCFG("mixins.stellar_core_lazyae2.json", "lazyae2"); - addModdedMixinCFG("mixins.stellar_core_legendarytooltips.json", "legendarytooltips"); - addModdedMixinCFG("mixins.stellar_core_libnine.json", "libnine", () -> StellarCoreConfig.PERFORMANCE.vanilla.parallelModelLoader); - addModdedMixinCFG("mixins.stellar_core_mek_top.json", new String[]{"mekanism", "theoneprobe"}, () -> StellarCoreConfig.FEATURES.mekanism.topSupport); - addMixinCFG( "mixins.stellar_core_mekanism.json", () -> Mods.MEK.loaded() && !Mods.MEKCEU.loaded()); - addModdedMixinCFG("mixins.stellar_core_mets.json", "mets"); - addModdedMixinCFG("mixins.stellar_core_modularrouters.json", "modularrouters"); - addModdedMixinCFG("mixins.stellar_core_nco.json", "nuclearcraft"); - addModdedMixinCFG("mixins.stellar_core_rgb_chat.json", "jianghun"); - addModdedMixinCFG("mixins.stellar_core_scalingguis.json", "scalingguis"); - addModdedMixinCFG("mixins.stellar_core_sync.json", "sync"); - addModdedMixinCFG("mixins.stellar_core_sync_techguns.json", "sync", "techguns"); - addModdedMixinCFG("mixins.stellar_core_tconevo.json", "tconevo"); - addModdedMixinCFG("mixins.stellar_core_tconstruct.json", "tconstruct"); - addModdedMixinCFG("mixins.stellar_core_techguns.json", "techguns"); - addModdedMixinCFG("mixins.stellar_core_theoneprobe.json", "theoneprobe"); - addModdedMixinCFG("mixins.stellar_core_thermaldynamics.json", "thermaldynamics"); - addModdedMixinCFG("mixins.stellar_core_thermalexpansion.json", "thermalexpansion", () -> StellarCoreConfig.BUG_FIXES.thermalExpansion.containerSatchelFilter); - addModdedMixinCFG("mixins.stellar_core_touhou_little_maid.json", "touhou_little_maid", () -> StellarCoreConfig.PERFORMANCE.tlm.modelDataCanonicalization); - addModdedMixinCFG("mixins.stellar_core_vintagefix.json", "vintagefix"); + addModdedMixinCFG("mixins.stellar_core_advancedrocketry.json", "advancedrocketry"); + addModdedMixinCFG("mixins.stellar_core_ae.json", "appliedenergistics2"); + addModdedMixinCFG("mixins.stellar_core_ancientspellcraft.json", "ancientspellcraft"); + addModdedMixinCFG("mixins.stellar_core_armourers_workshop.json", "armourers_workshop"); + addModdedMixinCFG("mixins.stellar_core_astralsorcery.json", "astralsorcery"); + addModdedMixinCFG("mixins.stellar_core_avaritia.json", "avaritia"); + addModdedMixinCFG("mixins.stellar_core_avaritiaddons.json", "avaritiaddons"); + addModdedMixinCFG("mixins.stellar_core_betterchat.json", "betterchat"); + addModdedMixinCFG("mixins.stellar_core_biomesoplenty.json", "biomesoplenty"); + addModdedMixinCFG("mixins.stellar_core_bloodmagic.json", "bloodmagic"); + addModdedMixinCFG("mixins.stellar_core_botania.json", "botania"); + addModdedMixinCFG("mixins.stellar_core_cfm.json", "cfm", () -> StellarCoreConfig.BUG_FIXES.mrCrayfishFurniture.imageCache); + addModdedMixinCFG("mixins.stellar_core_chisel.json", "chisel"); + addModdedMixinCFG("mixins.stellar_core_cofhcore.json", "cofhcore"); + addModdedMixinCFG("mixins.stellar_core_ctm.json", "ctm", () -> StellarCoreConfig.PERFORMANCE.ctm.textureMetadataHandler); + addModdedMixinCFG("mixins.stellar_core_cucumber.json", "cucumber"); + addModdedMixinCFG("mixins.stellar_core_customloadingscreen.json", "customloadingscreen"); + addModdedMixinCFG("mixins.stellar_core_customstartinggear.json", "customstartinggear"); + addModdedMixinCFG("mixins.stellar_core_draconicevolution.json", "draconicevolution"); + addModdedMixinCFG("mixins.stellar_core_ebwizardry.json", "ebwizardry"); + addModdedMixinCFG("mixins.stellar_core_endercore.json", "endercore"); + addModdedMixinCFG("mixins.stellar_core_enderio.json", "enderio"); + addModdedMixinCFG("mixins.stellar_core_enderioconduits.json", "enderio", "enderioconduits"); + addModdedMixinCFG("mixins.stellar_core_enderioconduits_energy.json", "enderio", "enderioconduits"); + addModdedMixinCFG("mixins.stellar_core_enderutilities.json", "enderutilities"); + addModdedMixinCFG("mixins.stellar_core_extrabotany.json", "extrabotany"); + addModdedMixinCFG("mixins.stellar_core_fluxnetworks.json", "fluxnetworks"); + addModdedMixinCFG("mixins.stellar_core_ftblib.json", "ftblib"); + addModdedMixinCFG("mixins.stellar_core_ftbquests.json", "ftbquests"); + addModdedMixinCFG("mixins.stellar_core_guguutils.json", "gugu-utils"); + addModdedMixinCFG("mixins.stellar_core_ic2.json", "ic2"); + addModdedMixinCFG("mixins.stellar_core_ic2_energynet.json", "ic2", () -> StellarCoreConfig.PERFORMANCE.industrialCraft2.energyCalculatorLeg); + addModdedMixinCFG("mixins.stellar_core_igi.json", "ingameinfoxml"); + addModdedMixinCFG("mixins.stellar_core_immersiveengineering.json", "immersiveengineering"); + addModdedMixinCFG("mixins.stellar_core_jei.json", "jei", () -> StellarCoreConfig.PERFORMANCE.vanilla.stitcherCache); + addModdedMixinCFG("mixins.stellar_core_threng.json", "threng"); + addModdedMixinCFG("mixins.stellar_core_legendarytooltips.json", "legendarytooltips"); + addModdedMixinCFG("mixins.stellar_core_libnine.json", "libnine", () -> StellarCoreConfig.PERFORMANCE.vanilla.parallelModelLoader); + addModdedMixinCFG("mixins.stellar_core_mek_top.json", new String[]{"mekanism", "theoneprobe"}, () -> StellarCoreConfig.FEATURES.mekanism.topSupport); + addMixinCFG( "mixins.stellar_core_mekanism.json", () -> Mods.MEK.loaded() && !Mods.MEKCEU.loaded()); + addModdedMixinCFG("mixins.stellar_core_mets.json", "mets"); + addModdedMixinCFG("mixins.stellar_core_modularrouters.json", "modularrouters"); + addModdedMixinCFG("mixins.stellar_core_nco.json", "nuclearcraft"); + addModdedMixinCFG("mixins.stellar_core_rgb_chat.json", "jianghun"); + addModdedMixinCFG("mixins.stellar_core_scalingguis.json", "scalingguis"); + addModdedMixinCFG("mixins.stellar_core_sync.json", "sync"); + addModdedMixinCFG("mixins.stellar_core_sync_techguns.json", "sync", "techguns"); + addModdedMixinCFG("mixins.stellar_core_tconevo.json", "tconevo"); + addModdedMixinCFG("mixins.stellar_core_tconstruct.json", "tconstruct"); + addModdedMixinCFG("mixins.stellar_core_techguns.json", "techguns"); + addModdedMixinCFG("mixins.stellar_core_theoneprobe.json", "theoneprobe"); + addModdedMixinCFG("mixins.stellar_core_thermaldynamics.json", "thermaldynamics"); + addModdedMixinCFG("mixins.stellar_core_thermalexpansion.json", "thermalexpansion", () -> StellarCoreConfig.BUG_FIXES.thermalExpansion.containerSatchelFilter); + addModdedMixinCFG("mixins.stellar_core_touhou_little_maid.json", "touhou_little_maid", () -> StellarCoreConfig.PERFORMANCE.tlm.modelDataCanonicalization); + addModdedMixinCFG("mixins.stellar_core_vintagefix.json", "vintagefix"); } @Override @@ -79,12 +81,12 @@ public List<String> getMixinConfigs() { public boolean shouldMixinConfigQueue(final String mixinConfig) { BooleanSupplier supplier = MIXIN_CONFIGS.get(mixinConfig); if (supplier == null) { - StellarLog.LOG.warn(StellarLog.LOG_PREFIX + "Mixin config {} is not found in config map! It will never be loaded.", mixinConfig); + StellarLog.LOG.warn("[StellarCore-MixinLoader] Mixin config {} is not found in config map! It will never be loaded.", mixinConfig); return false; } boolean shouldLoad = supplier.getAsBoolean(); if (!shouldLoad) { - StellarLog.LOG.info(StellarLog.LOG_PREFIX + "Mixin config {} is disabled by config or mod is not loaded.", mixinConfig); + StellarLog.LOG.info("[StellarCore-MixinLoader] Mixin config {} is disabled by config or mod is not loaded.", mixinConfig); } return shouldLoad; } diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/enderio/MixinServerTickHandler.java b/src/main/java/github/kasuminova/stellarcore/mixin/enderio/MixinServerTickHandler.java new file mode 100644 index 0000000..358e08e --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/enderio/MixinServerTickHandler.java @@ -0,0 +1,42 @@ +package github.kasuminova.stellarcore.mixin.enderio; + +import crazypants.enderio.base.handler.ServerTickHandler; +import github.kasuminova.stellarcore.mixin.util.IStellarServerTickListener; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.profiler.Profiler; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +@Mixin(value = ServerTickHandler.class, remap = false) +public class MixinServerTickHandler { + + @Unique + private static final List<IStellarServerTickListener> FINAL_TICK_LISTENERS = new ObjectArrayList<>(); + + @Inject( + method = "lambda$onWorldTick$3", + at = @At( + value = "INVOKE", + target = "Lcrazypants/enderio/base/handler/ServerTickHandler$IServerTickListener;tickEnd(Lnet/minecraft/profiler/Profiler;)V", + shift = At.Shift.AFTER + ) + ) + private static void injectOnWorldTickTickListenerEnd(final Profiler profiler, final TickEvent.WorldTickEvent event, final ServerTickHandler.IServerTickListener listener, final String name, final CallbackInfo ci) { + if (listener instanceof IStellarServerTickListener stellarListener) { + FINAL_TICK_LISTENERS.add(stellarListener); + } + } + + @Inject(method = "onWorldTick", at = @At("RETURN")) + private static void injectOnWorldTickEnd(final TickEvent.WorldTickEvent event, final CallbackInfo ci) { + FINAL_TICK_LISTENERS.forEach(IStellarServerTickListener::tickFinal); + FINAL_TICK_LISTENERS.clear(); + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/AccessorReceptorEntry.java b/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/AccessorReceptorEntry.java new file mode 100644 index 0000000..b48cda7 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/AccessorReceptorEntry.java @@ -0,0 +1,27 @@ +package github.kasuminova.stellarcore.mixin.enderioconduits_energy; + +import crazypants.enderio.base.power.IPowerInterface; +import crazypants.enderio.conduits.conduit.power.IPowerConduit; +import crazypants.enderio.conduits.conduit.power.PowerConduitNetwork; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(value = PowerConduitNetwork.ReceptorEntry.class, remap = false) +public interface AccessorReceptorEntry { + + @Invoker + IPowerInterface invokeGetPowerInterface(); + + @Accessor + IPowerConduit getEmmiter(); + + @Accessor + BlockPos getPos(); + + @Accessor + EnumFacing getDirection(); + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinCapBankSupply.java b/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinCapBankSupply.java new file mode 100644 index 0000000..d04eaeb --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinCapBankSupply.java @@ -0,0 +1,75 @@ +package github.kasuminova.stellarcore.mixin.enderioconduits_energy; + +import crazypants.enderio.base.power.IPowerStorage; +import github.kasuminova.stellarcore.mixin.util.ICapBankSupply; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import javax.annotation.Nonnull; +import java.util.Set; + +@SuppressWarnings("AddedMixinMembersNamePattern") +@Mixin(targets = "crazypants.enderio.conduits.conduit.power.NetworkPowerManager$CapBankSupply", remap = false) +public abstract class MixinCapBankSupply implements ICapBankSupply { + + @Shadow + int canFill; + + @Shadow + int canExtract; + + @Shadow + @Final + @Nonnull + Set<IPowerStorage> capBanks; + + @Shadow + abstract void init(); + + @Shadow + abstract void balance(); + + @Shadow + abstract void remove(final long amount); + + @Shadow + abstract long add(final long amount); + + @Override + public int getCanExtract() { + return canExtract; + } + + @Override + public int getCanFill() { + return canFill; + } + + @Nonnull + @Override + public Set<IPowerStorage> getCapBanks() { + return capBanks; + } + + @Override + public void invokeInit() { + init(); + } + + @Override + public void invokeBalance() { + balance(); + } + + @Override + public void invokeRemove(final long remove) { + remove(remove); + } + + @Override + public long invokeAdd(final long add) { + return add(add); + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinNetworkPowerManager.java b/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinNetworkPowerManager.java new file mode 100644 index 0000000..0763030 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinNetworkPowerManager.java @@ -0,0 +1,225 @@ +package github.kasuminova.stellarcore.mixin.enderioconduits_energy; + +import crazypants.enderio.base.power.IPowerInterface; +import crazypants.enderio.conduits.conduit.power.IPowerConduit; +import crazypants.enderio.conduits.conduit.power.NetworkPowerManager; +import crazypants.enderio.conduits.conduit.power.PowerConduitNetwork; +import crazypants.enderio.conduits.conduit.power.PowerTracker; +import github.kasuminova.stellarcore.common.config.StellarCoreConfig; +import github.kasuminova.stellarcore.common.util.StellarLog; +import github.kasuminova.stellarcore.mixin.util.ICapBankSupply; +import github.kasuminova.stellarcore.mixin.util.IStellarNetworkPowerManager; +import github.kasuminova.stellarcore.mixin.util.ReceptorPowerInterface; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.profiler.Profiler; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import javax.annotation.Nonnull; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + +@Mixin(value = NetworkPowerManager.class, remap = false) +public abstract class MixinNetworkPowerManager implements IStellarNetworkPowerManager { + + // Shadows... + + @Shadow + @Final + @Nonnull + private PowerTracker networkPowerTracker; + + @Shadow + private long energyStored; + + @Shadow + @Final + @Nonnull + private List<PowerConduitNetwork.ReceptorEntry> receptors; + + @Shadow + @Final + @Nonnull + private List<PowerConduitNetwork.ReceptorEntry> storageReceptors; + + @Shadow + protected abstract void trackerStartTick(); + + @Shadow + protected abstract void trackerEndTick(); + + @Shadow + protected abstract void trackerSend(@Nonnull final IPowerConduit con, final int sent, final boolean fromBank); + + @Shadow + protected abstract void checkReceptors(); + + @Shadow + protected abstract void updateNetworkStorage(); + + @Shadow + protected abstract void distributeStorageToConduits(); + + // Unique fields... + + @Unique + private final List<ReceptorPowerInterface> stellar_core$collectedPowerInterface = new ObjectArrayList<>(); + + @Unique + private Future<Void> stellar_core$parallelTask = null; + + @Unique + private volatile boolean stellar_core$shouldFinalApply = false; + + // Reflections... + + @Unique + private static volatile MethodHandle stellar_core$getCapSupply = null; + + /** + * @author Kasumi_Nova + * @reason Rewrite to parallel exec. + */ + @Inject(method = "doApplyRecievedPower", at = @At("HEAD"), cancellable = true) + public void doApplyRecievedPower(final Profiler theProfiler, final CallbackInfo ci) { + if (!StellarCoreConfig.PERFORMANCE.enderIOConduits.networkPowerManager) { + return; + } + ci.cancel(); + + trackerStartTick(); + checkReceptors(); + + stellar_core$parallelTask = CompletableFuture.runAsync(() -> { + // Update our energy stored based on what's in our conduits + updateNetworkStorage(); + networkPowerTracker.tickStart(energyStored); + + ICapBankSupply capSupply = stellar_core$getCapSupply(); + capSupply.invokeInit(); + + long available = energyStored + capSupply.getCanExtract(); + + if (available <= 0 || (receptors.isEmpty() && storageReceptors.isEmpty())) { + trackerEndTick(); + networkPowerTracker.tickEnd(energyStored); + stellar_core$shouldFinalApply = false; + return; + } + + stellar_core$collectedPowerInterface.clear(); + receptors.forEach(receptor -> { + AccessorReceptorEntry accessorReceptorEntry = (AccessorReceptorEntry) receptor; + IPowerInterface pp = accessorReceptorEntry.invokeGetPowerInterface(); + if (pp != null) { + stellar_core$collectedPowerInterface.add(new ReceptorPowerInterface(pp, accessorReceptorEntry)); + } + }); + stellar_core$shouldFinalApply = true; + }); + } + + @Unique + @Override + @SuppressWarnings("AddedMixinMembersNamePattern") + public void finalApplyReceivedPower() { + if (!StellarCoreConfig.PERFORMANCE.enderIOConduits.networkPowerManager) { + return; + } + + if (stellar_core$parallelTask != null && !stellar_core$parallelTask.isDone()) { + try { + stellar_core$parallelTask.get(); + } catch (Throwable e) { + StellarLog.LOG.warn("[StellarCore-MixinNetworkPowerManager] Error while waiting for parallel task to finish!", e); + } + } + stellar_core$parallelTask = null; + if (!stellar_core$shouldFinalApply) { + return; + } + + // 我们已经在 doApplyRecievedPower 执行过一次 updateNetworkStorage 了,为什么他妈还要在这里跑一次? + updateNetworkStorage(); + ICapBankSupply capSupply = stellar_core$getCapSupply(); + + long available = energyStored + capSupply.getCanExtract(); + long wasAvailable = available; + + for (final ReceptorPowerInterface rpp : stellar_core$collectedPowerInterface) { + AccessorReceptorEntry r = rpp.receptor(); + IPowerInterface pp = rpp.pp(); + + int canOffer = (int) Math.min(r.getEmmiter().getMaxEnergyExtracted(r.getDirection()), available); + int used = Math.max(0, pp.receiveEnergy(canOffer, false)); + trackerSend(r.getEmmiter(), used, false); + available -= used; + + if (available <= 0) { + break; + } + } + + long used = wasAvailable - available; + // use all the capacator storage first + energyStored -= used; + + if (!capSupply.getCapBanks().isEmpty()) { + long capBankChange = 0; + if (energyStored < 0) { + // not enough so get the rest from the capacitor bank + capBankChange = energyStored; + energyStored = 0; + } else if (energyStored > 0) { + // push as much as we can back to the cap banks + capBankChange = Math.min(energyStored, capSupply.getCanFill()); + energyStored -= capBankChange; + } + + if (capBankChange < 0) { + capSupply.invokeRemove(Math.abs(capBankChange)); + } else if (capBankChange > 0) { + energyStored += capSupply.invokeAdd(capBankChange); + } + + capSupply.invokeBalance(); + } + + distributeStorageToConduits(); + + trackerEndTick(); + + networkPowerTracker.tickEnd(energyStored); + } + + @SuppressWarnings("DataFlowIssue") + @Unique + private ICapBankSupply stellar_core$getCapSupply() { + if (stellar_core$getCapSupply == null) { + synchronized (NetworkPowerManager.class) { + if (stellar_core$getCapSupply == null) { + try { + stellar_core$getCapSupply = MethodHandles.lookup().unreflectGetter(NetworkPowerManager.class.getDeclaredField("capSupply")); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + } + + try { + return (ICapBankSupply) stellar_core$getCapSupply.invoke((NetworkPowerManager) (Object) this); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinPowerConduitNetwork.java b/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinPowerConduitNetwork.java new file mode 100644 index 0000000..8b679ad --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/enderioconduits_energy/MixinPowerConduitNetwork.java @@ -0,0 +1,31 @@ +package github.kasuminova.stellarcore.mixin.enderioconduits_energy; + +import crazypants.enderio.conduits.conduit.AbstractConduitNetwork; +import crazypants.enderio.conduits.conduit.power.IPowerConduit; +import crazypants.enderio.conduits.conduit.power.NetworkPowerManager; +import crazypants.enderio.conduits.conduit.power.PowerConduitNetwork; +import github.kasuminova.stellarcore.mixin.util.IStellarNetworkPowerManager; +import github.kasuminova.stellarcore.mixin.util.IStellarServerTickListener; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(value = PowerConduitNetwork.class, remap = false) +public abstract class MixinPowerConduitNetwork extends AbstractConduitNetwork<IPowerConduit, IPowerConduit> implements IStellarServerTickListener { + + @Shadow + NetworkPowerManager powerManager; + + @SuppressWarnings("DataFlowIssue") + protected MixinPowerConduitNetwork() { + super(null, null); + } + + @Unique + @Override + @SuppressWarnings("AddedMixinMembersNamePattern") + public void tickFinal() { + ((IStellarNetworkPowerManager) powerManager).finalApplyReceivedPower(); + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinCommonProxy.java b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinCommonProxy.java new file mode 100644 index 0000000..9f7a2c1 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinCommonProxy.java @@ -0,0 +1,34 @@ +package github.kasuminova.stellarcore.mixin.fluxnetworks; + +import github.kasuminova.stellarcore.mixin.util.IStellarFluxNetwork; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import sonar.fluxnetworks.api.network.IFluxNetwork; +import sonar.fluxnetworks.common.CommonProxy; +import sonar.fluxnetworks.common.connection.FluxNetworkCache; + +import java.util.Collection; +import java.util.List; + +@SuppressWarnings("MethodMayBeStatic") +@Mixin(value = CommonProxy.class, remap = false) +public class MixinCommonProxy { + + @Inject(method = "onServerTick", at = @At("HEAD")) + private void injectOnServerTick(final TickEvent.ServerTickEvent event, final CallbackInfo ci) { + if (event.phase == TickEvent.Phase.END) { + Collection<IFluxNetwork> networks = FluxNetworkCache.instance.getAllNetworks(); + List<Runnable> runnableList = new ObjectArrayList<>(networks.size() + 1); + networks.stream().filter(IStellarFluxNetwork.class::isInstance) + .map(IStellarFluxNetwork.class::cast) + .map(IStellarFluxNetwork::getCycleStartRunnable) + .forEach(runnableList::add); + runnableList.parallelStream().forEach(Runnable::run); + } + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinConnectionTransfer.java b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinConnectionTransfer.java new file mode 100644 index 0000000..83b9885 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinConnectionTransfer.java @@ -0,0 +1,54 @@ +package github.kasuminova.stellarcore.mixin.fluxnetworks; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import org.spongepowered.asm.mixin.*; +import sonar.fluxnetworks.api.energy.ITileEnergyHandler; +import sonar.fluxnetworks.common.connection.transfer.ConnectionTransfer; + +@Mixin(value = ConnectionTransfer.class, remap = false) +public class MixinConnectionTransfer { + + @Shadow + @Final + private ITileEnergyHandler energyHandler; + + @Shadow + @Final + private TileEntity tile; + + @Shadow + @Final + private EnumFacing side; + + @Shadow + public long inbound; + + @Unique + private boolean stellar_core$canAddEnergy = false; + + /** + * @author Kasumi_Nova + * @reason Selective judgement + */ + @Overwrite + public long sendToTile(long amount, boolean simulate) { + if (simulate) { + if (energyHandler.canAddEnergy(tile, side)) { + stellar_core$canAddEnergy = true; + return energyHandler.addEnergy(amount, tile, side, true); + } + stellar_core$canAddEnergy = false; + return 0; + } + + if (stellar_core$canAddEnergy) { + stellar_core$canAddEnergy = false; + long added = energyHandler.addEnergy(amount, tile, side, false); + inbound += added; + return added; + } + return 0; + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkCache.java b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkCache.java new file mode 100644 index 0000000..4aaa19a --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkCache.java @@ -0,0 +1,34 @@ +package github.kasuminova.stellarcore.mixin.fluxnetworks; + +import github.kasuminova.stellarcore.common.config.StellarCoreConfig; +import github.kasuminova.stellarcore.common.util.RandomUtils; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import sonar.fluxnetworks.api.network.IFluxNetwork; +import sonar.fluxnetworks.common.connection.FluxNetworkCache; +import sonar.fluxnetworks.common.data.FluxNetworkData; + +import java.util.Map; + +@SuppressWarnings("MethodMayBeStatic") +@Mixin(value = FluxNetworkCache.class, remap = false) +public class MixinFluxNetworkCache { + + @Inject(method = "getUniqueID", at = @At("HEAD"), cancellable = true) + private void injectGetUniqueID(final CallbackInfoReturnable<Integer> cir) { + if (!StellarCoreConfig.FEATURES.fluxNetworks.randomNetworkUniqueID) { + return; + } + + Map<Integer, IFluxNetwork> networks = FluxNetworkData.get().networks; + int newID = RandomUtils.nextInt(); + while (newID == -1 || networks.containsKey(newID)) { + newID = RandomUtils.nextInt(); + } + + cir.setReturnValue(newID); + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkServer.java b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkServer.java index faef519..89c1f46 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkServer.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/fluxnetworks/MixinFluxNetworkServer.java @@ -1,16 +1,27 @@ package github.kasuminova.stellarcore.mixin.fluxnetworks; import github.kasuminova.stellarcore.common.config.StellarCoreConfig; +import github.kasuminova.stellarcore.mixin.util.IStellarFluxNetwork; import net.minecraft.entity.player.EntityPlayer; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import sonar.fluxnetworks.api.network.AccessLevel; +import sonar.fluxnetworks.api.network.FluxLogicType; +import sonar.fluxnetworks.api.network.IFluxNetwork; import sonar.fluxnetworks.api.network.NetworkMember; +import sonar.fluxnetworks.api.tiles.IFluxConnector; +import sonar.fluxnetworks.api.tiles.IFluxPlug; +import sonar.fluxnetworks.api.tiles.IFluxPoint; import sonar.fluxnetworks.common.connection.FluxNetworkBase; import sonar.fluxnetworks.common.connection.FluxNetworkServer; +import sonar.fluxnetworks.common.connection.PriorityGroup; +import sonar.fluxnetworks.common.connection.TransferIterator; import java.util.List; import java.util.Optional; @@ -18,7 +29,84 @@ @SuppressWarnings("SynchronizeOnNonFinalField") @Mixin(value = FluxNetworkServer.class, remap = false) -public class MixinFluxNetworkServer extends FluxNetworkBase { +public abstract class MixinFluxNetworkServer extends FluxNetworkBase implements IFluxNetwork, IStellarFluxNetwork { + + @Shadow + protected abstract void handleConnectionQueue(); + + @Shadow + public long bufferLimiter; + + @Shadow + @Final + private List<PriorityGroup<IFluxPoint>> sortedPoints; + + @Shadow + @Final + private List<PriorityGroup<IFluxPlug>> sortedPlugs; + + @Shadow + @Final + private TransferIterator<IFluxPlug> plugTransferIterator; + + @Shadow + @Final + private TransferIterator<IFluxPoint> pointTransferIterator; + + @Override + @SuppressWarnings("AddedMixinMembersNamePattern") + public Runnable getCycleStartRunnable() { + handleConnectionQueue(); + return () -> { + List<IFluxConnector> devices = getConnections(FluxLogicType.ANY); + devices.parallelStream().forEach(device -> device.getTransferHandler().onCycleStart()); + }; + } + + /** + * @author Kasumi_Nova + * @reason Parallel Execution + */ + @Overwrite + public void onEndServerTick() { + network_stats.getValue().startProfiling(); + + bufferLimiter = 0; + + List<IFluxConnector> devices = getConnections(FluxLogicType.ANY); + + if (!sortedPoints.isEmpty() && !sortedPlugs.isEmpty()) { + plugTransferIterator.reset(sortedPlugs); + pointTransferIterator.reset(sortedPoints); + CYCLE: + while (pointTransferIterator.hasNext()) { + while (plugTransferIterator.hasNext()) { + IFluxPlug plug = plugTransferIterator.next(); + IFluxPoint point = pointTransferIterator.next(); + if (plug.getConnectionType() == point.getConnectionType()) { + break CYCLE; // Storage always have the lowest priority, the cycle can be broken here. + } + // we don't need to simulate this action + long operate = plug.getTransferHandler().removeFromBuffer(point.getTransferHandler().getRequest()); + if (operate > 0) { + point.getTransferHandler().addToBuffer(operate); + continue CYCLE; + } else { + // although the plug still need transfer (buffer > 0) + // but it reached max transfer limit, so we use next plug + plugTransferIterator.incrementFlux(); + } + } + break; // all plugs have been used + } + } + for (IFluxConnector f : devices) { + f.getTransferHandler().onCycleEnd(); + bufferLimiter += f.getTransferHandler().getRequest(); + } + + network_stats.getValue().stopProfiling(); + } @Inject( method = "getMemberPermission", @@ -35,7 +123,7 @@ private void injectGetMemberPermission(final EntityPlayer player, final Callback } UUID uuid = EntityPlayer.getUUID(player.getGameProfile()); - + synchronized (network_players) { for (final NetworkMember member : network_players.getValue()) { if (member.getPlayerUUID().equals(uuid)) { diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/ic2/AccessorGridChange.java b/src/main/java/github/kasuminova/stellarcore/mixin/ic2/AccessorGridChange.java new file mode 100644 index 0000000..76c8797 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/ic2/AccessorGridChange.java @@ -0,0 +1,22 @@ +package github.kasuminova.stellarcore.mixin.ic2; + +import ic2.api.energy.tile.IEnergyTile; +import net.minecraft.util.math.BlockPos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(targets = "ic2.core.energy.grid.GridChange", remap = false) +public interface AccessorGridChange { + + @Accessor + BlockPos getPos(); + + @Accessor + IEnergyTile getIoTile(); + + @Accessor + List<IEnergyTile> getSubTiles(); + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/ic2/MixinEnergyNetLocal.java b/src/main/java/github/kasuminova/stellarcore/mixin/ic2/MixinEnergyNetLocal.java index 1bf6c45..4c11cb5 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/ic2/MixinEnergyNetLocal.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/ic2/MixinEnergyNetLocal.java @@ -1,28 +1,37 @@ package github.kasuminova.stellarcore.mixin.ic2; import github.kasuminova.stellarcore.common.config.StellarCoreConfig; +import github.kasuminova.stellarcore.common.util.BlockPos2IntMap; import github.kasuminova.stellarcore.common.util.BlockPos2ValueMap; +import ic2.api.energy.tile.IEnergyTile; import ic2.core.energy.grid.EnergyNetLocal; import ic2.core.energy.grid.Tile; import net.minecraft.util.math.BlockPos; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.lang.reflect.Field; import java.util.Map; +import java.util.Queue; @Mixin(value = EnergyNetLocal.class, remap = false) -public class MixinEnergyNetLocal { +public abstract class MixinEnergyNetLocal { @Final @Shadow @Mutable Map<BlockPos, Tile> registeredTiles; + @Unique + private final BlockPos2IntMap stellar_core$gridChangeCounter = new BlockPos2IntMap(); + + @Unique + private static final Object STELLAR_CORE$QUEUE_DELAY_CHANGE = stellar_core$getQueueDelayChange(); + @Inject(method = "<init>", at = @At("RETURN")) private void injectInit(final CallbackInfo ci) { if (!StellarCoreConfig.PERFORMANCE.industrialCraft2.energyNetLocal) { @@ -31,4 +40,60 @@ private void injectInit(final CallbackInfo ci) { this.registeredTiles = new BlockPos2ValueMap<>(); } + @Inject(method = "getIoTile", at = @At(value = "INVOKE", target = "Ljava/util/Queue;iterator()Ljava/util/Iterator;"), cancellable = true) + private void injectGetIOTileBeforeScanQueue(final BlockPos pos, final CallbackInfoReturnable<IEnergyTile> cir) { + if (!StellarCoreConfig.PERFORMANCE.industrialCraft2.getIoAndSubTile) { + return; + } + if (stellar_core$gridChangeCounter.getInt(pos) <= 0) { + cir.setReturnValue(null); + } + } + + @Inject(method = "getSubTile", at = @At(value = "INVOKE", target = "Ljava/util/Queue;iterator()Ljava/util/Iterator;"), cancellable = true) + private void injectGetSubTileBeforeScan(final BlockPos pos, final CallbackInfoReturnable<IEnergyTile> cir) { + if (!StellarCoreConfig.PERFORMANCE.industrialCraft2.getIoAndSubTile) { + return; + } + if (stellar_core$gridChangeCounter.getInt(pos) <= 0) { + cir.setReturnValue(null); + } + } + + @Redirect(method = {"addTile", "removeTile"}, at = @At(value = "INVOKE", target = "Ljava/util/Queue;add(Ljava/lang/Object;)Z")) + private boolean redirectQueueAdd(final Queue<Object> instance, final Object e) { + if (e != STELLAR_CORE$QUEUE_DELAY_CHANGE && e instanceof AccessorGridChange gridChange) { + stellar_core$gridChangeCounter.addTo(gridChange.getPos(), 1); + } + return instance.add(e); + } + + @Redirect(method = "removeTile", at = @At(value = "INVOKE", target = "Ljava/util/Queue;remove(Ljava/lang/Object;)Z")) + private boolean redirectQueueRemove(final Queue<Object> instance, final Object e) { + if (e != STELLAR_CORE$QUEUE_DELAY_CHANGE && e instanceof AccessorGridChange gridChange) { + stellar_core$gridChangeCounter.addTo(gridChange.getPos(), -1); + } + return instance.remove(e); + } + + @Redirect(method = "onTickEnd", at = @At(value = "INVOKE", target = "Ljava/util/Queue;poll()Ljava/lang/Object;")) + private Object redirectQueuePoll(final Queue<Object> instance) { + Object polled = instance.poll(); + if (polled != STELLAR_CORE$QUEUE_DELAY_CHANGE && polled instanceof AccessorGridChange gridChange) { + stellar_core$gridChangeCounter.addTo(gridChange.getPos(), -1); + } + return polled; + } + + @Unique + private static Object stellar_core$getQueueDelayChange() { + try { + Field queueDelayChange = EnergyNetLocal.class.getDeclaredField("QUEUE_DELAY_CHANGE"); + queueDelayChange.setAccessible(true); + return queueDelayChange.get(null); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/ic2_energynet/MixinEnergyCalculatorLeg.java b/src/main/java/github/kasuminova/stellarcore/mixin/ic2_energynet/MixinEnergyCalculatorLeg.java new file mode 100644 index 0000000..41487b4 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/ic2_energynet/MixinEnergyCalculatorLeg.java @@ -0,0 +1,198 @@ +package github.kasuminova.stellarcore.mixin.ic2_energynet; + +import github.kasuminova.stellarcore.mixin.util.AccessorGridData; +import github.kasuminova.stellarcore.mixin.util.IC2EnergySyncCalcTask; +import github.kasuminova.stellarcore.mixin.util.IStellarEnergyCalculatorLeg; +import ic2.api.energy.EnergyNet; +import ic2.api.energy.tile.IEnergySink; +import ic2.api.energy.tile.IEnergySource; +import ic2.api.energy.tile.IMultiEnergySource; +import ic2.core.IC2; +import ic2.core.energy.grid.*; +import ic2.core.energy.leg.EnergyCalculatorLeg; +import ic2.core.util.LogCategory; +import ic2.core.util.Util; +import net.minecraft.world.World; +import org.apache.commons.lang3.mutable.MutableDouble; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; + +@Mixin(value = EnergyCalculatorLeg.class, remap = false) +public abstract class MixinEnergyCalculatorLeg implements IStellarEnergyCalculatorLeg { + + @Unique + private static volatile MethodHandle stellar_core$distribute = null; + + @Unique + private static volatile MethodHandle stellar_core$getData = null; + + @Shadow + @SuppressWarnings("rawtypes") + private static void applyCableEffects(final Collection eventPaths, final World world) { + } + + /** + * @author Kasumi_Nova + * @reason Parallel calculation + */ + @Overwrite + public boolean runSyncStep(EnergyNetLocal enet) { + final AtomicBoolean foundAny = new AtomicBoolean(false); + enet.getSources().parallelStream().forEach(tile -> { + IEnergySource source = (IEnergySource) tile.getMainTile(); + int packets = 1; + double amount; + if (tile.isDisabled() || !((amount = source.getOfferedEnergy()) > 0.0D) || + (source instanceof IMultiEnergySource multiSource && (multiSource).sendMultipleEnergyPackets() && (packets = multiSource.getMultipleEnergyPacketAmount()) <= 0)) { + tile.setSourceData(0.0D, 0); + return; + } + + int tier = source.getSourceTier(); + if (tier < 0) { + if (EnergyNetSettings.logGridCalculationIssues) { + IC2.log.warn(LogCategory.EnergyNet, "Tile %s reported an invalid tier (%d).", Util.toString(source, enet.getWorld(), EnergyNet.instance.getPos(source)), tier); + } + tile.setSourceData(0.0D, 0); + return; + } + foundAny.set(true); + double power = EnergyNet.instance.getPowerFromTier(tier); + amount = Math.min(amount, power * packets); + tile.setSourceData(amount, packets); + }); + return foundAny.get(); + } + + @Unique + @Override + @SuppressWarnings("AddedMixinMembersNamePattern") + public IC2EnergySyncCalcTask doParallelCalc(final Grid grid) { + AccessorGridData gridData = stellar_core$getData(grid); + if (!gridData.isActive()) { + return IC2EnergySyncCalcTask.EMPTY; + } + + List<Node> activeSources = gridData.getActiveSources(); + Map<Node, MutableDouble> activeSinks = gridData.getActiveSinks(); + + activeSources.clear(); + activeSinks.clear(); + + int calcId = gridData.incrementCurrentCalcId(); + + for (Node node : grid.getNodes()) { + Tile tile = node.getTile(); + if (tile.isDisabled()) { + continue; + } + if (node.getType() == NodeType.Source && gridData.getEnergySourceToEnergyPathMap().containsKey(node) && tile.getAmount() > 0.0D) { + activeSources.add(node); + continue; + } + double amount; + if (node.getType() == NodeType.Sink && (amount = ((IEnergySink) tile.getMainTile()).getDemandedEnergy()) > 0.0D) { + activeSinks.put(node, new MutableDouble(amount)); + } + } + + if (activeSources.isEmpty() || activeSinks.isEmpty()) { + return IC2EnergySyncCalcTask.EMPTY; + } + + World world = grid.getEnergyNet().getWorld(); + return new IC2EnergySyncCalcTask(world, calcId, grid, gridData, activeSources, activeSinks); + } + + @Override + @SuppressWarnings("AddedMixinMembersNamePattern") + public void doSyncCalc(final IC2EnergySyncCalcTask task) { + if (task == IC2EnergySyncCalcTask.EMPTY) { + return; + } + + World world = task.world(); + List<Node> activeSources = task.activeSources(); + Map<Node, MutableDouble> activeSinks = task.activeSinks(); + AccessorGridData gridData = task.gridData(); + int calcID = task.calcID(); + Grid grid = task.grid(); + + Random rand = world.rand; + boolean shufflePaths = ((world.getTotalWorldTime() & 0x3L) != 0L); + + int sourcesOffset; + if (activeSources.size() > 1) { + sourcesOffset = rand.nextInt(activeSources.size()); + } else { + sourcesOffset = 0; + } + + int i; + for (i = sourcesOffset; i < activeSources.size() && !activeSinks.isEmpty(); i++) { + stellar_core$distribute(activeSources.get(i), gridData, shufflePaths, calcID, rand); + } + for (i = 0; i < sourcesOffset && !activeSinks.isEmpty(); i++) { + stellar_core$distribute(activeSources.get(i), gridData, shufflePaths, calcID, rand); + } + + Set<Object> eventPaths = gridData.getEventPaths(); + if (!eventPaths.isEmpty()) { + applyCableEffects(eventPaths, grid.getEnergyNet().getWorld()); + eventPaths.clear(); + } + } + + @Unique + private static void stellar_core$distribute(final Node srcNode, final AccessorGridData gridData, final boolean shufflePaths, final int calcId, final Random rand) { + if (stellar_core$distribute == null) { + synchronized (EnergyCalculatorLeg.class) { + if (stellar_core$distribute == null) { + try { + stellar_core$distribute = MethodHandles.lookup().unreflect(EnergyCalculatorLeg.class.getDeclaredMethod( + "distribute", Node.class, Class.forName("ic2.core.energy.leg.EnergyCalculatorLeg$GridData"), boolean.class, int.class, Random.class + )); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + } + + try { + stellar_core$distribute.invoke(srcNode, gridData, shufflePaths, calcId, rand); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @Unique + private static AccessorGridData stellar_core$getData(final Grid grid) { + if (stellar_core$getData == null) { + synchronized (EnergyCalculatorLeg.class) { + if (stellar_core$getData == null) { + try { + stellar_core$getData = MethodHandles.lookup().unreflect(EnergyCalculatorLeg.class.getDeclaredMethod( + "getData", Grid.class + )); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + } + try { + return (AccessorGridData) stellar_core$getData.invoke(grid); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/ic2_energynet/MixinGridData.java b/src/main/java/github/kasuminova/stellarcore/mixin/ic2_energynet/MixinGridData.java new file mode 100644 index 0000000..d6e53cc --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/ic2_energynet/MixinGridData.java @@ -0,0 +1,86 @@ +package github.kasuminova.stellarcore.mixin.ic2_energynet; + +import github.kasuminova.stellarcore.mixin.util.AccessorGridData; +import ic2.core.energy.grid.Node; +import org.apache.commons.lang3.mutable.MutableDouble; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +@SuppressWarnings({"AddedMixinMembersNamePattern", "unchecked", "rawtypes"}) +@Mixin(targets = "ic2.core.energy.leg.EnergyCalculatorLeg$GridData", remap = false) +public class MixinGridData implements AccessorGridData { + + @Shadow + boolean active; + + @Shadow + @Final + Map energySourceToEnergyPathMap; + + @Shadow + @Final + List<Node> activeSources; + + @Shadow + @Final + Map<Node, MutableDouble> activeSinks; + + @Shadow + @Final + Set eventPaths; + + @Shadow + @Final + Map pathCache; + + @Shadow + int currentCalcId; + + @Override + public boolean isActive() { + return active; + } + + @Override + @SuppressWarnings("unchecked") + public Map<Node, List<Object>> getEnergySourceToEnergyPathMap() { + return (Map<Node, List<Object>>) (Map<?, ?>) energySourceToEnergyPathMap; + } + + @Override + public List<Node> getActiveSources() { + return activeSources; + } + + @Override + public Map<Node, MutableDouble> getActiveSinks() { + return activeSinks; + } + + @Override + public Set<Object> getEventPaths() { + return (Set<Object>) eventPaths; + } + + @Override + public Map<Node, List<Object>> getPathCache() { + return (Map<Node, List<Object>>) pathCache; + } + + @Override + public int currentCalcId() { + return currentCalcId; + } + + @Override + public int incrementCurrentCalcId() { + ++currentCalcId; + return currentCalcId; + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/ic2_energynet/MixinGridUpdater.java b/src/main/java/github/kasuminova/stellarcore/mixin/ic2_energynet/MixinGridUpdater.java new file mode 100644 index 0000000..8e44195 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/ic2_energynet/MixinGridUpdater.java @@ -0,0 +1,245 @@ +package github.kasuminova.stellarcore.mixin.ic2_energynet; + +import github.kasuminova.stellarcore.common.util.StellarLog; +import github.kasuminova.stellarcore.mixin.util.IC2EnergySyncCalcTask; +import github.kasuminova.stellarcore.mixin.util.IStellarEnergyCalculatorLeg; +import ic2.core.energy.grid.EnergyNetGlobal; +import ic2.core.energy.grid.EnergyNetLocal; +import ic2.core.energy.grid.Grid; +import ic2.core.energy.grid.IEnergyCalculator; +import io.netty.util.internal.shaded.org.jctools.queues.atomic.MpscLinkedAtomicQueue; +import org.spongepowered.asm.mixin.*; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.Queue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; + +@Mixin(targets = "ic2.core.energy.grid.GridUpdater", remap = false) +public class MixinGridUpdater { + + @Shadow + private boolean busy; + + @Shadow + private boolean isChangeStep; + + @Shadow + @Final + private EnergyNetLocal enet; + + @Unique + private static volatile MethodHandle stellar_core$gridCalcTaskConstructor = null; + + @Unique + private static volatile MethodHandle stellar_core$gridCalcTaskGridSetter = null; + + @Unique + private static volatile MethodHandle stellar_core$EnergyNetGlobal$getCalculator = null; + + @Unique + private static volatile MethodHandle stellar_core$EnergyNetLocal$hasGrids = null; + + @Unique + private static volatile MethodHandle stellar_core$EnergyNetLocal$getGrids = null; + + @Unique + private static volatile MethodHandle stellar_core$EnergyNetLocal$shuffleGrids = null; + + @Unique + private final Queue<IC2EnergySyncCalcTask> stellar_core$syncTaskQueue = stellar_core$createConcurrentQueue(); + + /** + * @author Kasumi_Nova + * @reason Parallel Calculation + */ + @Overwrite + void startTransferCalc() { + assert !this.busy; + this.isChangeStep = false; + IEnergyCalculator energyCalculator = stellar_core$EnergyNetGlobal$getCalculator(); + if (!stellar_core$EnergyNetLocal$hasGrids(enet) || !energyCalculator.runSyncStep(this.enet)) { + return; + } + + this.busy = true; + Collection<Grid> grids = stellar_core$EnergyNetLocal$getGrids(enet); + + IStellarEnergyCalculatorLeg stellarCalculator = (IStellarEnergyCalculatorLeg) energyCalculator; + + int completedTask = 0; + int tasks = grids.size(); + CompletableFuture.runAsync(() -> { + for (final Grid grid : grids) { + CompletableFuture.runAsync(() -> stellar_core$syncTaskQueue.offer(stellarCalculator.doParallelCalc(grid))); + } + }); + + while (completedTask < tasks) { + IC2EnergySyncCalcTask task = stellar_core$syncTaskQueue.poll(); + if (task == null) { + try { + Thread.sleep(0); // yield + } catch (InterruptedException ignored) { + } + continue; + } + stellarCalculator.doSyncCalc(task); + completedTask++; + } + + if (!stellar_core$syncTaskQueue.isEmpty()) { + StellarLog.LOG.warn("[StellarCore-IC2GridUpdater] Unable to complete all tasks, {} tasks left.", stellar_core$syncTaskQueue.size()); + stellar_core$syncTaskQueue.forEach(stellarCalculator::doSyncCalc); + stellar_core$syncTaskQueue.clear(); + } + + if (grids.size() > 1) { + stellar_core$EnergyNetLocal$shuffleGrids(enet); + } + + this.busy = false; + } + + @Unique + @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") + private static Object stellar_core$newGridCalcTask(final Object gridUpdater) { + if (stellar_core$gridCalcTaskConstructor == null) { + synchronized (gridUpdater) { + if (stellar_core$gridCalcTaskConstructor == null) { + try { + Constructor<?> constructor = Class.forName("ic2.core.energy.grid.GridUpdater$GridCalcTask").getDeclaredConstructor(Class.forName("ic2.core.energy.grid.GridUpdater")); + constructor.setAccessible(true); + stellar_core$gridCalcTaskConstructor = MethodHandles.lookup().unreflectConstructor(constructor); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + } + try { + return stellar_core$gridCalcTaskConstructor.invoke(gridUpdater); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @Unique + @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") + private static void stellar_core$setGridCalcTaskGrid(final Object gridCalcTask, final Grid grid) { + if (stellar_core$gridCalcTaskGridSetter == null) { + synchronized (gridCalcTask) { + if (stellar_core$gridCalcTaskGridSetter == null) { + try { + Field gridField = Class.forName("ic2.core.energy.grid.GridUpdater$GridCalcTask").getDeclaredField("grid"); +// gridField.setAccessible(true); + stellar_core$gridCalcTaskGridSetter = MethodHandles.lookup().unreflectSetter(gridField); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + } + try { + stellar_core$gridCalcTaskGridSetter.invoke(gridCalcTask, grid); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @Unique + private static IEnergyCalculator stellar_core$EnergyNetGlobal$getCalculator() { + if (stellar_core$EnergyNetGlobal$getCalculator == null) { + synchronized (EnergyNetGlobal.class) { + if (stellar_core$EnergyNetGlobal$getCalculator == null) { + try { + stellar_core$EnergyNetGlobal$getCalculator = MethodHandles.lookup().unreflect(Class.forName("ic2.core.energy.grid.EnergyNetGlobal").getDeclaredMethod("getCalculator")); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + } + try { + return (IEnergyCalculator) stellar_core$EnergyNetGlobal$getCalculator.invoke(); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @Unique + private static boolean stellar_core$EnergyNetLocal$hasGrids(final EnergyNetLocal enet) { + if (stellar_core$EnergyNetLocal$hasGrids == null) { + synchronized (EnergyNetLocal.class) { + if (stellar_core$EnergyNetLocal$hasGrids == null) { + try { + stellar_core$EnergyNetLocal$hasGrids = MethodHandles.lookup().unreflect(Class.forName("ic2.core.energy.grid.EnergyNetLocal").getDeclaredMethod("hasGrids")); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + } + try { + return (boolean) stellar_core$EnergyNetLocal$hasGrids.invoke(enet); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @Unique + @SuppressWarnings("unchecked") + private static Collection<Grid> stellar_core$EnergyNetLocal$getGrids(final EnergyNetLocal enet) { + if (stellar_core$EnergyNetLocal$getGrids == null) { + synchronized (EnergyNetLocal.class) { + if (stellar_core$EnergyNetLocal$getGrids == null) { + try { + stellar_core$EnergyNetLocal$getGrids = MethodHandles.lookup().unreflect(Class.forName("ic2.core.energy.grid.EnergyNetLocal").getDeclaredMethod("getGrids")); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + } + try { + return (Collection<Grid>) stellar_core$EnergyNetLocal$getGrids.invoke(enet); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @Unique + private static void stellar_core$EnergyNetLocal$shuffleGrids(final EnergyNetLocal enet) { + if (stellar_core$EnergyNetLocal$shuffleGrids == null) { + synchronized (EnergyNetLocal.class) { + if (stellar_core$EnergyNetLocal$shuffleGrids == null) { + try { + stellar_core$EnergyNetLocal$shuffleGrids = MethodHandles.lookup().unreflect(Class.forName("ic2.core.energy.grid.EnergyNetLocal").getDeclaredMethod("shuffleGrids")); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + } + try { + stellar_core$EnergyNetLocal$shuffleGrids.invoke(enet); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @Unique + private static <E> Queue<E> stellar_core$createConcurrentQueue() { + try { + // May be incompatible with cleanroom. + return new MpscLinkedAtomicQueue<>(); + } catch (Throwable e) { + return new ConcurrentLinkedQueue<>(); + } + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/immersiveengineering/MixinTileEntityMultiblockMetal.java b/src/main/java/github/kasuminova/stellarcore/mixin/immersiveengineering/MixinTileEntityMultiblockMetal.java new file mode 100644 index 0000000..30264c5 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/immersiveengineering/MixinTileEntityMultiblockMetal.java @@ -0,0 +1,22 @@ +package github.kasuminova.stellarcore.mixin.immersiveengineering; + +import blusunrize.immersiveengineering.common.blocks.metal.TileEntityMultiblockMetal; +import github.kasuminova.stellarcore.common.config.StellarCoreConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@SuppressWarnings("MethodMayBeStatic") +@Mixin(value = TileEntityMultiblockMetal.class, remap = false) +public class MixinTileEntityMultiblockMetal { + + @Inject(method = "postEnergyTransferUpdate", at = @At("HEAD"), cancellable = true) + private void injectPostEnergyTransferUpdate(final int energy, final boolean simulate, final CallbackInfo ci) { + if (!StellarCoreConfig.PERFORMANCE.immersiveEngineering.energyTransferNoUpdate) { + return; + } + ci.cancel(); + } + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/blockstateimpl/MixinStateImplementation.java b/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/blockstateimpl/MixinStateImplementation.java index a1d6f1c..4f367b1 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/blockstateimpl/MixinStateImplementation.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/blockstateimpl/MixinStateImplementation.java @@ -1,11 +1,15 @@ package github.kasuminova.stellarcore.mixin.minecraft.blockstateimpl; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableTable; +import net.minecraft.block.Block; import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @SuppressWarnings("NonFinalFieldReferencedInHashCode") @Mixin(BlockStateContainer.StateImplementation.class) @@ -18,8 +22,13 @@ public class MixinStateImplementation { @Unique private int stellar_core$hashCode; - @Inject(method = "<init>*", at = @At("RETURN")) - private void injectInit() { + @Inject(method = "<init>(Lnet/minecraft/block/Block;Lcom/google/common/collect/ImmutableMap;)V", at = @At("RETURN")) + private void injectInit(final Block blockIn, final ImmutableMap<IProperty<?>, Comparable<?>> propertiesIn, final CallbackInfo ci) { + this.stellar_core$hashCode = this.properties.hashCode(); + } + + @Inject(method = "<init>(Lnet/minecraft/block/Block;Lcom/google/common/collect/ImmutableMap;Lcom/google/common/collect/ImmutableTable;)V", at = @At("RETURN")) + private void injectInit(final Block blockIn, final ImmutableMap<IProperty<?>, Comparable<?>> propertiesIn, final ImmutableTable<IProperty<?>, Comparable<?>, IBlockState> propertyValueTable, final CallbackInfo ci) { this.stellar_core$hashCode = this.properties.hashCode(); } diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/chunk_cache/MixinChunk.java b/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/chunk_cache/MixinChunk.java index d25b3b5..231153e 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/chunk_cache/MixinChunk.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/chunk_cache/MixinChunk.java @@ -4,8 +4,8 @@ import github.kasuminova.stellarcore.common.config.StellarCoreConfig; import github.kasuminova.stellarcore.common.util.StellarLog; import github.kasuminova.stellarcore.mixin.util.CachedChunk; -import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; -import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.shorts.Short2ReferenceMap; +import it.unimi.dsi.fastutil.shorts.Short2ReferenceOpenHashMap; import net.minecraft.block.state.IBlockState; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; @@ -40,7 +40,7 @@ public class MixinChunk implements CachedChunk { public static ExtendedBlockStorage NULL_BLOCK_STORAGE; @Unique - private final Short2ObjectMap<IBlockState> stellar_core$blockStateCache = new Short2ObjectOpenHashMap<>(); + private final Short2ReferenceMap<IBlockState> stellar_core$blockStateCache = new Short2ReferenceOpenHashMap<>(); @Unique private boolean stellar_core$enableCache = false; @@ -155,7 +155,7 @@ private void injectSetStorageArrays(final ExtendedBlockStorage[] newStorageArray @Unique @Override - public Short2ObjectMap<IBlockState> stellar_core$getBlockStateCache() { + public Short2ReferenceMap<IBlockState> stellar_core$getBlockStateCache() { return stellar_core$blockStateCache; } diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/forge/parallelmodelloader/MixinModelLoader.java b/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/forge/parallelmodelloader/MixinModelLoader.java index 6d70b08..a5c7c94 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/forge/parallelmodelloader/MixinModelLoader.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/forge/parallelmodelloader/MixinModelLoader.java @@ -10,10 +10,7 @@ import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.client.renderer.BlockModelShapes; -import net.minecraft.client.renderer.block.model.IBakedModel; -import net.minecraft.client.renderer.block.model.ModelBakery; -import net.minecraft.client.renderer.block.model.ModelBlockDefinition; -import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.block.model.*; import net.minecraft.client.renderer.block.statemap.BlockStateMapper; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; @@ -127,6 +124,10 @@ private void injectInit(final IResourceManager resourceManagerIn, final TextureM List<Block> blocks, @Local(name = "blockBar") ProgressManager.ProgressBar blockBar, @Local(name = "mapper") BlockStateMapper mapper) { + // It Loaded? Don't remove this local var. + //noinspection unused + Class<ModelRotation> ModelRotation = ModelRotation.class; + long startTime = System.currentTimeMillis(); stellar_core$toConcurrent(); @@ -252,7 +253,7 @@ private void injectInit(final IResourceManager resourceManagerIn, final TextureM @Unique private static void stellar_core$addAlias(ResourceLocation from, ResourceLocation to) { try { - stellar_core$addAlias.invoke(null, from, to); + stellar_core$addAlias.invoke(from, to); } catch (Throwable e) { throw new RuntimeException(e); } @@ -261,7 +262,7 @@ private void injectInit(final IResourceManager resourceManagerIn, final TextureM @Unique private static IModel stellar_core$getMissingModel(ResourceLocation location, Throwable cause) { try { - return (IModel) stellar_core$getMissingModel.invoke(null, location, cause); + return (IModel) stellar_core$getMissingModel.invoke(location, cause); } catch (Throwable e) { throw new RuntimeException(e); } diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/randomtick/MixinWorldServer.java b/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/randomtick/MixinWorldServer.java index 5b80fbe..2116cb6 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/randomtick/MixinWorldServer.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/randomtick/MixinWorldServer.java @@ -4,6 +4,7 @@ import github.kasuminova.stellarcore.common.world.ParallelRandomBlockTicker; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; @@ -15,7 +16,6 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.LinkedList; import java.util.List; @Mixin(WorldServer.class) @@ -38,8 +38,9 @@ protected MixinWorldServer() { ) private ExtendedBlockStorage[] redirectUpdateBlocksGetBlockStorageArray(final Chunk chunk, final @Local(name = "i") int tickSpeed) { int updateLCG = this.updateLCG; - List<ParallelRandomBlockTicker.TickData> tickDataList = new LinkedList<>(); - for (ExtendedBlockStorage storage : chunk.getBlockStorageArray()) { + ExtendedBlockStorage[] storageArray = chunk.getBlockStorageArray(); + List<ParallelRandomBlockTicker.TickData> tickDataList = new ObjectArrayList<>(storageArray.length + 1); + for (ExtendedBlockStorage storage : storageArray) { if (storage == Chunk.NULL_BLOCK_STORAGE || !storage.needsRandomTick()) { continue; } diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/statemapperbase/MixinStateMapperBase.java b/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/statemapperbase/MixinStateMapperBase.java index 782f6ab..8a92b57 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/statemapperbase/MixinStateMapperBase.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/minecraft/statemapperbase/MixinStateMapperBase.java @@ -1,5 +1,6 @@ package github.kasuminova.stellarcore.mixin.minecraft.statemapperbase; +import github.kasuminova.stellarcore.common.config.StellarCoreConfig; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import net.minecraft.block.state.IBlockState; import net.minecraft.client.renderer.block.model.ModelResourceLocation; @@ -11,6 +12,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; @Mixin(StateMapperBase.class) public class MixinStateMapperBase { @@ -20,6 +22,10 @@ public class MixinStateMapperBase { @Inject(method = "<init>", at = @At("RETURN"), remap = false) private void injectInit(final CallbackInfo ci) { + if (StellarCoreConfig.PERFORMANCE.vanilla.parallelModelLoader) { + this.mapStateModelLocations = new ConcurrentHashMap<>(); + return; + } this.mapStateModelLocations = new Object2ObjectLinkedOpenHashMap<>(); } diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/lazyae2/MixinInventoryRequest.java b/src/main/java/github/kasuminova/stellarcore/mixin/threng/MixinInventoryRequest.java similarity index 95% rename from src/main/java/github/kasuminova/stellarcore/mixin/lazyae2/MixinInventoryRequest.java rename to src/main/java/github/kasuminova/stellarcore/mixin/threng/MixinInventoryRequest.java index e471647..39d83ea 100644 --- a/src/main/java/github/kasuminova/stellarcore/mixin/lazyae2/MixinInventoryRequest.java +++ b/src/main/java/github/kasuminova/stellarcore/mixin/threng/MixinInventoryRequest.java @@ -1,4 +1,4 @@ -package github.kasuminova.stellarcore.mixin.lazyae2; +package github.kasuminova.stellarcore.mixin.threng; import github.kasuminova.stellarcore.common.config.StellarCoreConfig; import io.github.phantamanta44.threng.tile.TileLevelMaintainer; diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/util/AccessorGridData.java b/src/main/java/github/kasuminova/stellarcore/mixin/util/AccessorGridData.java new file mode 100644 index 0000000..225ffc2 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/util/AccessorGridData.java @@ -0,0 +1,28 @@ +package github.kasuminova.stellarcore.mixin.util; + +import ic2.core.energy.grid.Node; +import org.apache.commons.lang3.mutable.MutableDouble; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public interface AccessorGridData { + + boolean isActive(); + + Map<Node, List<Object>> getEnergySourceToEnergyPathMap(); + + List<Node> getActiveSources(); + + Map<Node, MutableDouble> getActiveSinks(); + + Set<Object> getEventPaths(); + + Map<Node, List<Object>> getPathCache(); + + int currentCalcId(); + + int incrementCurrentCalcId(); + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/util/IC2EnergySyncCalcTask.java b/src/main/java/github/kasuminova/stellarcore/mixin/util/IC2EnergySyncCalcTask.java new file mode 100644 index 0000000..ae111a6 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/util/IC2EnergySyncCalcTask.java @@ -0,0 +1,17 @@ +package github.kasuminova.stellarcore.mixin.util; + +import com.github.bsideup.jabel.Desugar; +import ic2.core.energy.grid.Grid; +import ic2.core.energy.grid.Node; +import net.minecraft.world.World; +import org.apache.commons.lang3.mutable.MutableDouble; + +import java.util.List; +import java.util.Map; + +@Desugar +public record IC2EnergySyncCalcTask(World world, int calcID, Grid grid, AccessorGridData gridData, List<Node> activeSources, Map<Node, MutableDouble> activeSinks) { + + public static final IC2EnergySyncCalcTask EMPTY = new IC2EnergySyncCalcTask(null, 0, null, null, null, null); + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/util/ICapBankSupply.java b/src/main/java/github/kasuminova/stellarcore/mixin/util/ICapBankSupply.java new file mode 100644 index 0000000..2eb0637 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/util/ICapBankSupply.java @@ -0,0 +1,23 @@ +package github.kasuminova.stellarcore.mixin.util; + +import crazypants.enderio.base.power.IPowerStorage; + +import java.util.Set; + +public interface ICapBankSupply { + + int getCanExtract(); + + int getCanFill(); + + Set<IPowerStorage> getCapBanks(); + + void invokeInit(); + + void invokeBalance(); + + void invokeRemove(long remove); + + long invokeAdd(long add); + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarEnergyCalculatorLeg.java b/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarEnergyCalculatorLeg.java new file mode 100644 index 0000000..ce63517 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarEnergyCalculatorLeg.java @@ -0,0 +1,11 @@ +package github.kasuminova.stellarcore.mixin.util; + +import ic2.core.energy.grid.Grid; + +public interface IStellarEnergyCalculatorLeg { + + IC2EnergySyncCalcTask doParallelCalc(final Grid grid); + + void doSyncCalc(final IC2EnergySyncCalcTask task); + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarFluxNetwork.java b/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarFluxNetwork.java new file mode 100644 index 0000000..af31353 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarFluxNetwork.java @@ -0,0 +1,7 @@ +package github.kasuminova.stellarcore.mixin.util; + +public interface IStellarFluxNetwork { + + Runnable getCycleStartRunnable(); + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarNetworkPowerManager.java b/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarNetworkPowerManager.java new file mode 100644 index 0000000..d3bb230 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarNetworkPowerManager.java @@ -0,0 +1,7 @@ +package github.kasuminova.stellarcore.mixin.util; + +public interface IStellarNetworkPowerManager { + + void finalApplyReceivedPower(); + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarServerTickListener.java b/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarServerTickListener.java new file mode 100644 index 0000000..ef2c5a9 --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/util/IStellarServerTickListener.java @@ -0,0 +1,7 @@ +package github.kasuminova.stellarcore.mixin.util; + +public interface IStellarServerTickListener { + + void tickFinal(); + +} diff --git a/src/main/java/github/kasuminova/stellarcore/mixin/util/ReceptorPowerInterface.java b/src/main/java/github/kasuminova/stellarcore/mixin/util/ReceptorPowerInterface.java new file mode 100644 index 0000000..3df5e7e --- /dev/null +++ b/src/main/java/github/kasuminova/stellarcore/mixin/util/ReceptorPowerInterface.java @@ -0,0 +1,9 @@ +package github.kasuminova.stellarcore.mixin.util; + +import com.github.bsideup.jabel.Desugar; +import crazypants.enderio.base.power.IPowerInterface; +import github.kasuminova.stellarcore.mixin.enderioconduits_energy.AccessorReceptorEntry; + +@Desugar +public record ReceptorPowerInterface(IPowerInterface pp, AccessorReceptorEntry receptor) { +} diff --git a/src/main/resources/mixins.stellar_core_enderio.json b/src/main/resources/mixins.stellar_core_enderio.json index f9504cf..ebc3059 100644 --- a/src/main/resources/mixins.stellar_core_enderio.json +++ b/src/main/resources/mixins.stellar_core_enderio.json @@ -8,6 +8,7 @@ "MixinCommune", "MixinItemTools", "MixinRecipe", + "MixinServerTickHandler", "MixinTileEntityBase" ] } \ No newline at end of file diff --git a/src/main/resources/mixins.stellar_core_enderioconduits_energy.json b/src/main/resources/mixins.stellar_core_enderioconduits_energy.json new file mode 100644 index 0000000..be8ffa9 --- /dev/null +++ b/src/main/resources/mixins.stellar_core_enderioconduits_energy.json @@ -0,0 +1,13 @@ +{ + "package": "github.kasuminova.stellarcore.mixin.enderioconduits_energy", + "refmap": "mixins.stellar_core.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "AccessorReceptorEntry", + "MixinCapBankSupply", + "MixinNetworkPowerManager", + "MixinPowerConduitNetwork" + ] +} \ No newline at end of file diff --git a/src/main/resources/mixins.stellar_core_fluxnetworks.json b/src/main/resources/mixins.stellar_core_fluxnetworks.json index cc2f6d2..34a9c88 100644 --- a/src/main/resources/mixins.stellar_core_fluxnetworks.json +++ b/src/main/resources/mixins.stellar_core_fluxnetworks.json @@ -5,6 +5,9 @@ "minVersion": "0.8", "compatibilityLevel": "JAVA_8", "mixins": [ + "MixinCommonProxy", + "MixinConnectionTransfer", + "MixinFluxNetworkCache", "MixinFluxNetworkServer", "MixinTOPIntegration" ] diff --git a/src/main/resources/mixins.stellar_core_ic2.json b/src/main/resources/mixins.stellar_core_ic2.json index b9efff2..4a00338 100644 --- a/src/main/resources/mixins.stellar_core_ic2.json +++ b/src/main/resources/mixins.stellar_core_ic2.json @@ -8,6 +8,7 @@ "MixinItemBattery" ], "mixins": [ + "AccessorGridChange", "MixinBaseElectricItem", "MixinElectricItemManager", "MixinEnergyCalculatorLegGridData", diff --git a/src/main/resources/mixins.stellar_core_ic2_energynet.json b/src/main/resources/mixins.stellar_core_ic2_energynet.json new file mode 100644 index 0000000..13c4f16 --- /dev/null +++ b/src/main/resources/mixins.stellar_core_ic2_energynet.json @@ -0,0 +1,12 @@ +{ + "package": "github.kasuminova.stellarcore.mixin.ic2_energynet", + "refmap": "mixins.stellar_core.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "MixinEnergyCalculatorLeg", + "MixinGridData", + "MixinGridUpdater" + ] +} \ No newline at end of file diff --git a/src/main/resources/mixins.stellar_core_immersiveengineering.json b/src/main/resources/mixins.stellar_core_immersiveengineering.json index 2ea3150..80e92dc 100644 --- a/src/main/resources/mixins.stellar_core_immersiveengineering.json +++ b/src/main/resources/mixins.stellar_core_immersiveengineering.json @@ -7,9 +7,10 @@ "mixins": [ "MixinBlockIEMultiblock", "MixinBlockIETileProvider", - "MixinThreadContributorSpecialsDownloader", "MixinRecipeJerrycan", + "MixinThreadContributorSpecialsDownloader", "MixinTileEntityArcFurnace", - "MixinTileEntityExcavator" + "MixinTileEntityExcavator", + "MixinTileEntityMultiblockMetal" ] } \ No newline at end of file diff --git a/src/main/resources/mixins.stellar_core_lazyae2.json b/src/main/resources/mixins.stellar_core_threng.json similarity index 76% rename from src/main/resources/mixins.stellar_core_lazyae2.json rename to src/main/resources/mixins.stellar_core_threng.json index 129c0bc..1aee74c 100644 --- a/src/main/resources/mixins.stellar_core_lazyae2.json +++ b/src/main/resources/mixins.stellar_core_threng.json @@ -1,5 +1,5 @@ { - "package": "github.kasuminova.stellarcore.mixin.lazyae2", + "package": "github.kasuminova.stellarcore.mixin.threng", "refmap": "mixins.stellar_core.refmap.json", "target": "@env(DEFAULT)", "minVersion": "0.8",