Files
TiedUp-/src/main/java/com/tiedup/remake/mixin/MixinMCAOpenAIChatAI.java
NotEvil f6466360b6 Clean repo for open source release
Remove build artifacts, dev tool configs, unused dependencies,
and third-party source dumps. Add proper README, update .gitignore,
clean up Makefile.
2026-04-12 00:51:22 +02:00

130 lines
4.5 KiB
Java

package com.tiedup.remake.mixin;
import com.tiedup.remake.compat.mca.MCACompat;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.compat.mca.ai.chatai.TiedUpModule;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.dialogue.GagTalkManager;
import com.tiedup.remake.state.IBondageState;
import java.util.List;
import java.util.Optional;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
/**
* Mixin for MCA's OpenAIChatAI to integrate TiedUp bondage context.
*
* <p>This mixin:
* <ul>
* <li>Injects TiedUp state into the AI context (tied, gagged, blindfolded, etc.)</li>
* <li>Transforms AI responses with gagtalk if the villager is gagged</li>
* </ul>
*
* <p>Note: Uses @Pseudo for soft dependency - only applies if MCA is present.
*/
@Pseudo
@Mixin(targets = "forge.net.mca.entity.ai.chatAI.OpenAIChatAI", remap = false)
public class MixinMCAOpenAIChatAI {
/**
* Inject TiedUp context after MCA's modules are applied.
*
* <p>We capture the 'input' list local variable and add our TiedUp context to it.
* This is called after PlayerModule.apply() which is the last module in the chain.
*/
@Inject(
method = "answer",
at = @At(
value = "INVOKE",
target = "Lforge/net/mca/entity/ai/chatAI/modules/PlayerModule;apply(Ljava/util/List;Lforge/net/mca/entity/VillagerEntityMCA;Lnet/minecraft/server/network/ServerPlayerEntity;)V",
shift = At.Shift.AFTER
),
locals = LocalCapture.CAPTURE_FAILSOFT,
require = 0 // Soft requirement - don't crash if not found
)
private void tiedup$injectBondageContext(
Object player, // ServerPlayerEntity
Object villager, // VillagerEntityMCA
String msg,
CallbackInfoReturnable<Optional<String>> cir,
// Local variables captured (order matters!)
Object config,
boolean isInHouse,
String playerName,
String villagerName,
long time,
List<?> pastDialogue,
List<String> input
) {
try {
if (
villager instanceof LivingEntity living &&
player instanceof net.minecraft.world.entity.player.Player p
) {
TiedUpModule.apply(input, living, p);
TiedUpMod.LOGGER.debug(
"[MCA AI] Injected TiedUp context for {}",
living.getName().getString()
);
}
} catch (Exception e) {
TiedUpMod.LOGGER.debug(
"[MCA AI] Failed to inject context: {}",
e.getMessage()
);
}
}
/**
* Transform the AI response with gagtalk if the villager is gagged.
*
* <p>Intercepts the return value and applies gagtalk transformation
* using TiedUp's GagTalkManager.
*/
@Inject(
method = "answer",
at = @At("RETURN"),
cancellable = true,
require = 0
)
private void tiedup$transformGaggedResponse(
Object player, // ServerPlayerEntity
Object villager, // VillagerEntityMCA
String msg,
CallbackInfoReturnable<Optional<String>> cir
) {
try {
Optional<String> result = cir.getReturnValue();
if (result == null || result.isEmpty()) return;
if (!(villager instanceof LivingEntity living)) return;
IBondageState state = MCACompat.getKidnappedState(living);
if (state == null || !state.isGagged()) return;
// Apply gagtalk transformation
ItemStack gag = state.getEquipment(BodyRegionV2.MOUTH);
String gaggedResponse = GagTalkManager.transformToGaggedSpeech(
result.get(),
gag
);
TiedUpMod.LOGGER.debug("[MCA AI] Applied gagtalk to AI response");
cir.setReturnValue(Optional.of(gaggedResponse));
} catch (Exception e) {
TiedUpMod.LOGGER.debug(
"[MCA AI] Failed to transform gagged response: {}",
e.getMessage()
);
}
}
}