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. * *

This mixin: *

* *

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. * *

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> cir, // Local variables captured (order matters!) Object config, boolean isInHouse, String playerName, String villagerName, long time, List pastDialogue, List 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. * *

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> cir ) { try { Optional 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() ); } } }