com.yungnickyoung.minecraft.yungsapi.mixin.EntityProcessorMixinFabric Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of YungsApi-1.21-Fabric Show documentation
Show all versions of YungsApi-1.21-Fabric Show documentation
A common API for YUNG's Minecraft mods
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();
}
}
}