Skip to content

Commit

Permalink
Added Programmed Upgrade for AE2
Browse files Browse the repository at this point in the history
  • Loading branch information
Taskeren committed Aug 28, 2024
1 parent 5072c47 commit 5dd1892
Show file tree
Hide file tree
Showing 19 changed files with 349 additions and 4 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@ Check out [here](https://github.com/GTNewHorizons/RetroFuturaGradle/issues/51#is
- `UNDERLINE`
- `ITALIC`
- `RESET`

### Credits

- Texture of Programmed Upgrade is from [Neeve's AE2: Extended Life Additions (NAE2)](https://github.com/AE2-UEL/NAE2)
1 change: 1 addition & 0 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ dependencies {

implementation("com.github.GTNewHorizons:GT5-Unofficial:5.09.48.66:dev")
implementation("com.github.GTNewHorizons:NewHorizonsCoreMod:2.5.16:dev")
implementation("com.github.GTNewHorizons:AE2FluidCraft-Rework:1.3.26-gtnh")

// FIXME: publish TST to somewhere else
implementation("com.github.GTNewHorizons:Twist-Space-Technology-Mod:0.5.8-publish.11+344150b931-dirty")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package cn.taskeren.op.mixin.late;

import appeng.api.config.Upgrades;
import appeng.parts.automation.UpgradeInventory;
import cn.taskeren.op.ae.OP_AEUpgrades;
import com.llamalad7.mixinextras.sugar.Local;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(value = UpgradeInventory.class, remap = false)
public abstract class AdditionalAE_UpgradeInventory_Mixin {

/*
The additional upgrade items are registered as `OP_GeneratedAEUpgradeItem` and it implements IUpgradeModule, so we don't need to
do extra things in `isItemValidForSlot`.
In this class, we should manually count our custom upgrades and return the right value in the method.
*/

@Unique
private int op$programmedUpgrades = 0;

@Inject(method = "updateUpgradeInfo", at = @At("HEAD"))
private void op$updateUpgradeInfo_cleanse(CallbackInfo ci) {
op$programmedUpgrades = 0;
}

@Inject(method = "updateUpgradeInfo", at = @At(value = "INVOKE_ASSIGN", target = "Lappeng/api/implementations/items/IUpgradeModule;getType(Lnet/minecraft/item/ItemStack;)Lappeng/api/config/Upgrades;"))
private void op$updateUpgradeInfo_count(CallbackInfo ci, @Local(name = "myUpgrade") Upgrades myUpgrade) {
if(myUpgrade == OP_AEUpgrades.getProgrammedUpgrade()) {
op$programmedUpgrades++;
}
}

@Inject(method = "getInstalledUpgrades", at = @At("RETURN"), cancellable = true)
private void op$getInstalledUpgrades(Upgrades u, CallbackInfoReturnable<Integer> cir) {
// overwrite
if (u == OP_AEUpgrades.getProgrammedUpgrade()) {
cir.setReturnValue(op$programmedUpgrades);
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package cn.taskeren.op.mixin.late;

import appeng.api.config.Upgrades;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.gen.Invoker;

import java.util.ArrayList;
import java.util.Arrays;

@Mixin(value = Upgrades.class, remap = false)
@Unique
public abstract class AdditionalAE_Upgrades_Mixin {

/*
Added an extra instance to `Upgrades` enum.
This tricky method is from https://github.com/SpongePowered/Mixin/issues/387#issuecomment-888408556
But there is a potential bug that in the runtime the new created instance is added to the $VALUES twice, and
I cannot find the reason it is added twice. But it works for now, so I assume it affect nothing.
You should get the instance from `OP_AEUpgrades`.
*/

@Shadow
@Final
@Mutable
private static Upgrades[] $VALUES;

private static final Upgrades PROGRAMMED = op$createInstance("PROGRAMMED", 1);

@Invoker("<init>")
public static Upgrades op$constructor(String name, int ordinal, int tier) {
throw new AssertionError();
}

private static Upgrades op$createInstance(String name, int tier) {
// get existing instances
ArrayList<Upgrades> values = new ArrayList<>(Arrays.asList($VALUES));
// create the new instance
Upgrades value = op$constructor(name, values.get(values.size() - 1).ordinal() + 1, tier);
// add the new instance to the instance cache list
values.add(value);
// overwrite the $VALUES to the value list with the new instance
$VALUES = values.toArray(new Upgrades[0]);
// return the new instance
return value;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cn.taskeren.op.mixin.late;

import com.google.common.collect.Multimap;
import gregtech.api.GregTech_API;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

@Mixin(value = GregTech_API.class, remap = false)
public interface GTApi_GregTech_API_Mixin {

@Accessor("sRealConfigurationList")
static Multimap<Integer, ItemStack> getRealConfigurationList() {
throw new AssertionError();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cn.taskeren.op.mixin.late;

import appeng.api.config.Upgrades;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.helpers.DualityInterface;
import cn.taskeren.op.ae.OP_AEUpgrades;
import cn.taskeren.op.gt.utils.GTApi;
import codechicken.lib.inventory.InventoryUtils;
import com.llamalad7.mixinextras.sugar.Local;
import gregtech.api.interfaces.IConfigurationCircuitSupport;
import gregtech.api.metatileentity.BaseMetaTileEntity;
import gregtech.api.util.GT_Utility;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import org.spongepowered.asm.mixin.Mixin;
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.CallbackInfoReturnable;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Mixin(value = DualityInterface.class, remap = false)
public abstract class ProInterface_DualityInterface_Mixin {

@Shadow
private List<ItemStack> waitingToSend;

@Shadow
public abstract IInventory getStorage();

@Shadow
public abstract int getInstalledUpgrades(Upgrades u);

@Inject(method = "pushPattern", at = @At(value = "INVOKE", target = "Lappeng/helpers/DualityInterface;pushItemsOut(Ljava/util/EnumSet;)Z", ordinal = 0))
private void op$pushItemsOut(ICraftingPatternDetails patternDetails, InventoryCrafting table, CallbackInfoReturnable<Boolean> cir, @Local(name = "te") TileEntity tile) {
if(getInstalledUpgrades(OP_AEUpgrades.getProgrammedUpgrade()) < 1) { // requires the upgrade installed
return;
}

if(tile instanceof BaseMetaTileEntity) {
BaseMetaTileEntity bmte = (BaseMetaTileEntity) tile;
IConfigurationCircuitSupport circuitSupport = bmte.getConfigurationCircuitSupport();
if(circuitSupport != null) {
// get the first circuit stack in the items that will be inserted to the machine
Optional<ItemStack> circuitStackOptional = waitingToSend.stream()
.filter(Objects::nonNull)
.filter(GTApi.INSTANCE::isConfigurationCircuit).findFirst();

circuitStackOptional.ifPresent(circuitStack -> {
if (circuitSupport.getConfigurationCircuits().stream().anyMatch(allowedStack -> GT_Utility.areStacksEqual(allowedStack, circuitStack))) {
// set the circuit slot to the circuit stack
int circuitSlot = circuitSupport.getCircuitSlot();
bmte.getMetaTileEntity().setInventorySlotContents(circuitSlot, circuitStack.copy());
// remove the circuit stack from items that will be inserted to the machine
waitingToSend.remove(circuitStack);
// and return the circuit stack to the interface storage
InventoryUtils.insertItem(getStorage(), circuitStack, false);
}
});
}
}
}

}
19 changes: 19 additions & 0 deletions src/main/java/cn/taskeren/op/utils/MixinAccessorBridge.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cn.taskeren.op.utils;

import cn.taskeren.op.mixin.late.GTApi_GregTech_API_Mixin;
import com.google.common.collect.Multimap;
import net.minecraft.item.ItemStack;

/**
* This class is a bridge that used to access {@link org.spongepowered.asm.mixin.gen.Accessor}s in Kotlin while not throwing {@link IncompatibleClassChangeError}.
*/
public class MixinAccessorBridge {

/**
* @return gregtech.api.GregTech_API#sRealConfigurationList
*/
public static Multimap<Integer, ItemStack> getRealConfigurationList() {
return GTApi_GregTech_API_Mixin.getRealConfigurationList();
}

}
40 changes: 40 additions & 0 deletions src/main/kotlin/cn/taskeren/op/ae/OP_AEUpgrades.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package cn.taskeren.op.ae

import appeng.api.AEApi
import appeng.api.config.Upgrades
import cn.taskeren.op.OP_Logger
import com.glodblock.github.loader.ItemAndBlockHolder as AE2FCItemAndBlockHolder

/**
* @see cn.taskeren.op.mixin.late.AdditionalAE_Upgrades_Mixin
*/
object OP_AEUpgrades : OP_Logger {

/**
* @return the instance of Programmed Upgrade, or `null` if the mixin is failed or AE2 is not available.
*/
@JvmStatic
val programmedUpgrade: Upgrades? by lazy { runCatching { Upgrades.valueOf("PROGRAMMED") }.getOrNull() }

/**
* @return the available OP additional upgrades.
*/
@JvmStatic
val upgrades: List<Upgrades> by lazy { listOf(programmedUpgrade).filterNotNull() }

fun init() {
val aeApi = AEApi.instance()

// add upgrades to the allowlist of the ae2 parts and blocks
if(programmedUpgrade != null) {
logger.info("Programmed Upgrade is found!")
// ae2
programmedUpgrade?.registerItem(aeApi.definitions().parts().iface(), 1)
programmedUpgrade?.registerItem(aeApi.definitions().blocks().iface(), 1)
// ae2fc
programmedUpgrade?.registerItem(AE2FCItemAndBlockHolder.FLUID_INTERFACE.stack(), 1)
programmedUpgrade?.registerItem(AE2FCItemAndBlockHolder.INTERFACE.stack(), 1)
}
}

}
2 changes: 2 additions & 0 deletions src/main/kotlin/cn/taskeren/op/forge/CommonInit.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cn.taskeren.op.forge

import cn.taskeren.op.OP_Logger
import cn.taskeren.op.ae.OP_AEUpgrades
import cn.taskeren.op.forge.config.OP_Config
import cn.taskeren.op.gt.init.LazyScheduler
import cn.taskeren.op.gt.init.OP_GTRegistrar
Expand Down Expand Up @@ -38,6 +39,7 @@ open class CommonInit : OP_Logger {
}

open fun postInit(e: FMLPostInitializationEvent) {
OP_AEUpgrades.init()

LazyScheduler.runPostInit()
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/cn/taskeren/op/forge/OP_Mod.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import cpw.mods.fml.common.event.FMLServerStartingEvent
dependencies = "required-after:gregtech;" +
"required-after:miscutils;" + // gt++
"required-after:tectech;" + // TecTech
"required-after:dreamcraft;"
"required-after:dreamcraft;" +
"required-after:appliedenergistics2;" // AE2
)
object OP_Mod : OP_Logger {

Expand Down
4 changes: 3 additions & 1 deletion src/main/kotlin/cn/taskeren/op/gt/IdItemContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ fun IdItemContainer.addRecipe(recipeMap: IRecipeMap, block: GT_RecipeBuilder.(de
}
}

fun IdItemContainer.addRecipeSimple(block: (defaultItem: ItemStack) -> Unit) = apply {
fun IdItemContainer.useItemStackPostInit(block: (defaultItem: ItemStack) -> Unit) = apply {
LazyScheduler.schedulePostInit {
block(get(1))
}
}

fun IdItemContainer.addRecipeSimple(block: (defaultItem: ItemStack) -> Unit) = useItemStackPostInit(block)
34 changes: 32 additions & 2 deletions src/main/kotlin/cn/taskeren/op/gt/init/OP_GTRegistrar.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package cn.taskeren.op.gt.init

import appeng.api.AEApi
import cn.taskeren.op.ae.OP_AEUpgrades
import cn.taskeren.op.gt.addRecipe
import cn.taskeren.op.gt.addRecipeSimple
import cn.taskeren.op.gt.item.OP_GeneratedAEUpgradeItem
import cn.taskeren.op.gt.item.OP_GeneratedItem
import cn.taskeren.op.gt.item.impl.ActiveTransformerExplosionCoreItemBehaviour
import cn.taskeren.op.gt.item.impl.InsuranceReceiptItemBehaviour
Expand All @@ -13,6 +16,7 @@ import cn.taskeren.op.gt.single.OP_DebugEnergyHatch
import cn.taskeren.op.gt.single.OP_InsuranceCounter
import cn.taskeren.op.gt.single.OP_OverpowerMachine
import cn.taskeren.op.gt.single.OP_UniHatch
import cn.taskeren.op.gt.useItemStackPostInit
import cn.taskeren.op.gt.utils.PatternRecipeBuilder
import cn.taskeren.op.gt.utils.PatternRecipeBuilder.X
import com.github.technus.tectech.thing.CustomItemList
Expand All @@ -23,6 +27,7 @@ import gregtech.api.enums.TierEU
import gregtech.api.recipe.RecipeMaps
import gregtech.api.util.GT_ModHandler
import gregtech.api.util.GT_RecipeBuilder
import gregtech.api.util.GT_Utility
import gtPlusPlus.xmod.gregtech.api.enums.GregtechItemList
import net.minecraft.item.ItemStack
import com.dreammaster.gthandler.CustomItemList as DreamItemList
Expand All @@ -31,6 +36,7 @@ object OP_GTRegistrar {

fun registerAllMachines() {
registerSimpleItems()
registerAdditionalAEUpgrades()
registerSingleMachines()
}

Expand All @@ -57,13 +63,13 @@ object OP_GTRegistrar {
// #tr gt.metaitem.op.32003.name
// #en Insurance Receipt
// #zh 保险单
addItem(it, "Insurance Receipt", "", InsuranceReceiptItemBehaviour)
addItem(it, "Insurance Receipt", null, InsuranceReceiptItemBehaviour)
}
OP_ItemList.ActiveTransformerExplosionCore.registerItem {
// #tr gt.metaitem.op.32004.name
// #en Active Transformer Explosion Core
// #zh 有源变压器爆炸核心
addItem(it, "Active Transformer Explosion Core", "", ActiveTransformerExplosionCoreItemBehaviour)
addItem(it, "Active Transformer Explosion Core", null, ActiveTransformerExplosionCoreItemBehaviour)
}.addRecipe(RecipeMaps.hammerRecipes) {
itemInputs(CustomItemList.Machine_Multi_Transformer.get(1)) // active transformer
itemOutputs(it.copy().also { it.stackSize = 8 })
Expand All @@ -72,6 +78,30 @@ object OP_GTRegistrar {
}
}

private fun registerAdditionalAEUpgrades() = with(OP_GeneratedAEUpgradeItem) {
OP_ItemList.ProgrammedUpgrade.registerItem {
// #tr gt.metaitem.op.ae.32000.name
// #en Programmed Upgrade
// #zh 编程卡
// #tr gt.metaitem.op.ae.32000.tooltip
// #en Adjust Configuration Circuit by Pattern
// #zh 根据样板调整虚拟电路板
addItem(it, "Programmed Upgrade", "Adjust Configuration Circuit by Pattern")
}.useItemStackPostInit {
registerUpgrade(it, OP_AEUpgrades.programmedUpgrade)
}.addRecipeSimple {
val definitions = AEApi.instance().definitions()
GT_ModHandler.addCraftingRecipe(
it,
arrayOf(
"BC",
'B', definitions.materials().basicCard().maybeStack(1).get(),
'C', GT_Utility.getIntegratedCircuit(0)
)
)
}
}

private fun registerSingleMachines() {
// #tr gt.blockmachines.overpower_machine.name
// #en Incredible Malicious Machine Overpowering System
Expand Down
Loading

0 comments on commit 5dd1892

Please sign in to comment.