All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yungnickyoung.minecraft.yungsapi.mixin.EntityProcessorMixinFabric Maven / Gradle / Ivy

The newest version!
package com.yungnickyoung.minecraft.yungsapi.mixin;

import com.yungnickyoung.minecraft.yungsapi.world.processor.StructureEntityProcessor;
import com.yungnickyoung.minecraft.yungsapi.world.processor.StructureProcessingContext;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import net.minecraft.class_1297;
import net.minecraft.class_1299;
import net.minecraft.class_1308;
import net.minecraft.class_2338;
import net.minecraft.class_2415;
import net.minecraft.class_243;
import net.minecraft.class_2470;
import net.minecraft.class_2487;
import net.minecraft.class_2489;
import net.minecraft.class_2499;
import net.minecraft.class_3341;
import net.minecraft.class_3491;
import net.minecraft.class_3492;
import net.minecraft.class_3499;
import net.minecraft.class_3730;
import net.minecraft.class_5425;
import net.minecraft.class_5819;

/**
 * Allows for processing entities in Jigsaw structures.
 */
@Mixin(class_3499.class)
public class EntityProcessorMixinFabric {
    @Shadow
    @Final
    private List entityInfoList;

    @Unique
    private static final ThreadLocal context = new ThreadLocal<>();

    @Inject(
            method = "placeInWorld",
            at = @At(
                    value = "INVOKE",
                    target = "Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate;placeEntities(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/Mirror;Lnet/minecraft/world/level/block/Rotation;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/levelgen/structure/BoundingBox;Z)V"))
    private void yungsapi_captureContext(class_5425 serverLevelAccessor, class_2338 structurePiecePos, class_2338 structurePiecePivotPos,
                                         class_3492 structurePlaceSettings, class_5819 randomSource, int i, CallbackInfoReturnable cir) {
        context.set(new StructureProcessingContext(
                serverLevelAccessor,
                structurePlaceSettings,
                structurePiecePos,
                structurePiecePivotPos,
                entityInfoList
        ));
    }

    @Inject(
            method = "placeInWorld",
            at = @At(
                    value = "INVOKE",
                    shift = At.Shift.AFTER,
                    target = "Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate;placeEntities(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/Mirror;Lnet/minecraft/world/level/block/Rotation;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/levelgen/structure/BoundingBox;Z)V"))
    private void yungsapi_clearContext(class_5425 serverLevelAccessor, class_2338 structurePiecePos, class_2338 structurePiecePivotPos,
                                       class_3492 structurePlaceSettings, class_5819 randomSource, int i, CallbackInfoReturnable cir) {
        context.remove();
    }


    @Inject(
            method = "placeEntities",
            at = @At(value = "HEAD"),
            cancellable = true)
    private void yungsapi_processAndPlaceEntities(class_5425 serverLevelAccessor, class_2338 structurePiecePos, class_2415 mirror, class_2470 rotation, class_2338 pivot, class_3341 boundingBox, boolean bl, CallbackInfo ci) {
        StructureProcessingContext ctx = context.get();

        // If structure is not using YUNG's API entity processors, we don't need to do anything
        if (ctx.structurePlaceSettings().method_16182().stream().noneMatch(p -> p instanceof StructureEntityProcessor)) {
            return;
        }

        // Apply processors to entities
        List processedEntities = processEntityInfoList(ctx);

        // Place the processed entities
        for (class_3499.class_3502 entityInfo : processedEntities) {
            class_2338 entityBlockPos = entityInfo.field_15600;
            if (ctx.structurePlaceSettings().method_15124() == null|| ctx.structurePlaceSettings().method_15124().method_14662(entityBlockPos)) {
                class_2487 entityNbt = entityInfo.field_15598.method_10553();
                class_243 entityPos = entityInfo.field_15599;
                class_2499 listTag = new class_2499();
                listTag.add(class_2489.method_23241(entityPos.field_1352));
                listTag.add(class_2489.method_23241(entityPos.field_1351));
                listTag.add(class_2489.method_23241(entityPos.field_1350));
                entityNbt.method_10566("Pos", listTag);
                entityNbt.method_10551("UUID");
                tryCreateEntity(serverLevelAccessor, entityNbt).ifPresent((entity) -> {
                    float f = entity.method_5763(ctx.structurePlaceSettings().method_15114());
                    f += entity.method_36454() - entity.method_5832(ctx.structurePlaceSettings().method_15113());
                    entity.method_5808(entityPos.field_1352, entityPos.field_1351, entityPos.field_1350, f, entity.method_36455());
                    if (ctx.structurePlaceSettings().method_27265() && entity instanceof class_1308) {
                        ((class_1308) entity).method_5943(serverLevelAccessor, serverLevelAccessor.method_8404(class_2338.method_49638(entityPos)), class_3730.field_16474, null);
                    }

                    serverLevelAccessor.method_30771(entity);
                });
            }
        }

        // Cancel the original entity placement to prevent double-spawning entities.
        // Note that other mods like Porting Lib will still be able to run their own entity processors,
        // as long as the structure being processed is not also using YUNG's API entity processors.
        ci.cancel();
    }

    /**
     * Applies placement data and {@link StructureEntityProcessor}s to entities in a structure.
     *
     * @return A list of processed entities.
     */
    @Unique
    private List processEntityInfoList(StructureProcessingContext ctx) {
        List processedEntities = new ArrayList<>();

        // Extract context data
        class_5425 serverLevelAccessor = ctx.serverLevelAccessor();
        class_2338 structurePiecePos = ctx.structurePiecePos();
        class_2338 structurePiecePivotPos = ctx.structurePiecePivotPos();
        class_3492 structurePlaceSettings = ctx.structurePlaceSettings();
        List rawEntityInfos = ctx.rawEntityInfos();

        for (class_3499.class_3502 rawEntityInfo : rawEntityInfos) {
            // Calculate transformed position so processors have access to the actual global world coordinates of the entity
            class_243 globalPos = class_3499
                    .method_15176(rawEntityInfo.field_15599,
                            structurePlaceSettings.method_15114(),
                            structurePlaceSettings.method_15113(),
                            structurePlaceSettings.method_15134())
                    .method_1019(class_243.method_24954(structurePiecePos));
            class_2338 globalBlockPos = class_3499
                    .method_15168(rawEntityInfo.field_15600,
                            structurePlaceSettings.method_15114(),
                            structurePlaceSettings.method_15113(),
                            structurePlaceSettings.method_15134())
                    .method_10081(structurePiecePos);
            class_3499.class_3502 globalEntityInfo = new class_3499.class_3502(globalPos, globalBlockPos, rawEntityInfo.field_15598);

            // Apply processors
            for (class_3491 processor : structurePlaceSettings.method_16182()) {
                if (processor instanceof StructureEntityProcessor) {
                    globalEntityInfo = ((StructureEntityProcessor) processor).processEntity(serverLevelAccessor,structurePiecePos, structurePiecePivotPos, rawEntityInfo, globalEntityInfo, structurePlaceSettings);
                    if (globalEntityInfo == null) break;
                }
            }

            if (globalEntityInfo != null) { // null value from processor indicates the entity should not be spawned
                processedEntities.add(globalEntityInfo);
            }
        }

        return processedEntities;
    }

    /**
     * Attempts to create an entity from a CompoundTag.
     * If the entity cannot be created, returns an empty Optional.
     */
    @Unique
    private static Optional tryCreateEntity(class_5425 serverLevelAccessor, class_2487 compoundTag) {
        try {
            return class_1299.method_5892(compoundTag, serverLevelAccessor.method_8410());
        } catch (Exception exception) {
            return Optional.empty();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy