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

com.yungnickyoung.minecraft.yungsapi.world.structure.jigsaw.JigsawManager Maven / Gradle / Ivy

The newest version!
package com.yungnickyoung.minecraft.yungsapi.world.structure.jigsaw;

import com.mojang.datafixers.util.Pair;
import com.yungnickyoung.minecraft.yungsapi.YungsApiCommon;
import com.yungnickyoung.minecraft.yungsapi.mixin.accessor.StructureTemplatePoolAccessor;
import com.yungnickyoung.minecraft.yungsapi.util.BoxOctree;
import com.yungnickyoung.minecraft.yungsapi.world.structure.context.StructureContext;
import com.yungnickyoung.minecraft.yungsapi.world.structure.jigsaw.assembler.JigsawStructureAssembler;
import com.yungnickyoung.minecraft.yungsapi.world.structure.jigsaw.element.YungJigsawPoolElement;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.Optional;
import net.minecraft.class_156;
import net.minecraft.class_2338;
import net.minecraft.class_2378;
import net.minecraft.class_238;
import net.minecraft.class_2382;
import net.minecraft.class_2470;
import net.minecraft.class_2794;
import net.minecraft.class_2902;
import net.minecraft.class_2919;
import net.minecraft.class_2960;
import net.minecraft.class_3195;
import net.minecraft.class_3341;
import net.minecraft.class_3485;
import net.minecraft.class_3499;
import net.minecraft.class_3777;
import net.minecraft.class_3784;
import net.minecraft.class_3785;
import net.minecraft.class_3790;
import net.minecraft.class_5455;
import net.minecraft.class_5539;
import net.minecraft.class_5819;
import net.minecraft.class_6880;
import net.minecraft.class_7924;
import net.minecraft.class_9778;
import net.minecraft.class_9822;

public class JigsawManager {
    public static Optional assembleJigsawStructure(
            class_3195.class_7149 generationContext,
            class_6880 startPool,
            Optional startJigsawNameOptional,
            int maxDepth,
            class_2338 locatePos, // The original starting position of the structure, also where /locate points to
            boolean useExpansionHack, // Used to be doBoundaryAdjustments
            Optional projectStartToHeightmap,
            int maxDistanceFromCenter, // Used to be structureBoundingBoxRadius
            Optional maxY,
            Optional minY,
            class_9778 dimensionPadding,
            class_9822 liquidSettings

    ) {
        // Extract data from context
        class_5455 registryAccess = generationContext.comp_561();
        class_2794 chunkGenerator = generationContext.comp_562();
        class_3485 structureManager = generationContext.comp_565();
        class_5539 levelHeightAccessor = generationContext.comp_569();
        class_2919 worldgenRandom = generationContext.comp_566();
        class_2378 registry = registryAccess.method_30530(class_7924.field_41249);

        // Grab a random starting piece from the start pool
        Optional startPieceOptional = getStartPiece(startPool, startJigsawNameOptional, locatePos, structureManager, worldgenRandom, liquidSettings);
        if (startPieceOptional.isEmpty()) {
            return Optional.empty();
        }
        class_3790 startPiece = startPieceOptional.get();

        // Offset vector from the /locate position to the piece's starting position.
        // This will be a zero vector if no start jigsaw name was specified.
        class_2382 startingPosOffset = locatePos.method_10059(startPiece.method_16648());

        // Grab some data regarding starting piece's bounding box & position
        class_3341 pieceBoundingBox = startPiece.method_14935();
        int bbCenterX = (pieceBoundingBox.method_35418() + pieceBoundingBox.method_35415()) / 2;
        int bbCenterZ = (pieceBoundingBox.method_35420() + pieceBoundingBox.method_35417()) / 2;
        // Note that the bbCenterY does not actually refer to the center of the piece, unlike the bbCenterX/Z variables.
        // If a heightmap is used, the bbCenterY will be the y-value of the /locate position (anchor pos) after adjusting for the heightmap.
        // Otherwise, the bbCenterY is simply the starting position's y-value. I'm not sure why it uses that position and not the /locate position,
        // but that's vanilla behavior. It almost certainly won't make a difference anyway, as structures are basically never that tall.
        int bbCenterY = projectStartToHeightmap
                .map(types -> locatePos.method_10264() + chunkGenerator.method_20402(bbCenterX, bbCenterZ, types, levelHeightAccessor, generationContext.comp_564()))
                .orElseGet(() -> startPiece.method_16648().method_10264());
        int adjustedPieceCenterY = bbCenterY + startingPosOffset.method_10264();

        // Move the starting piece to account for any y-level change due to heightmap and/or groundLevelDelta
        int yAdjustment = pieceBoundingBox.method_35416() + startPiece.method_16646();
        startPiece.method_14922(0, bbCenterY - yAdjustment, 0);

        // Establish max bounds of entire structure.
        // Make sure the supplied distance is large enough to cover the size of your entire structure.
        class_238 aABB = new class_238(
                bbCenterX - maxDistanceFromCenter, adjustedPieceCenterY - maxDistanceFromCenter, bbCenterZ - maxDistanceFromCenter,
                bbCenterX + maxDistanceFromCenter + 1, adjustedPieceCenterY + maxDistanceFromCenter + 1, bbCenterZ + maxDistanceFromCenter + 1);
        BoxOctree maxStructureBounds = new BoxOctree(aABB); // The maximum boundary of the entire structure
        maxStructureBounds.addBox(class_238.method_19316(pieceBoundingBox)); // Add start piece to our structure's bounds

        return Optional.of(new class_3195.class_7150(
                new class_2338(bbCenterX, adjustedPieceCenterY, bbCenterZ),
                (structurePiecesBuilder) -> {
                    if (maxDepth <= 0) { // Realistically this should never be true. Why make a jigsaw config with a non-positive size?
                        return;
                    }

                    // Create assembler + initial entry
                    JigsawStructureAssembler assembler = new JigsawStructureAssembler(new JigsawStructureAssembler.Settings()
                            .poolRegistry(registry)
                            .maxDepth(maxDepth)
                            .chunkGenerator(chunkGenerator)
                            .structureTemplateManager(structureManager)
                            .randomState(generationContext.comp_564())
                            .rand(worldgenRandom)
                            .maxY(maxY)
                            .minY(minY)
                            .useExpansionHack(useExpansionHack)
                            .levelHeightAccessor(levelHeightAccessor)
                            .dimensionPadding(dimensionPadding)
                            .liquidSettings(liquidSettings));

                    // Add the start piece to the assembler & assemble the structure
                    assembler.assembleStructure(startPiece, maxStructureBounds);
                    assembler.addAllPiecesToStructureBuilder(structurePiecesBuilder);
                }));
    }

    /**
     * Returns a piece from the provided pool to be used as the starting piece for a structure.
     * Pieces are chosen randomly, but some conditions as well as the isPriority flag are respected.
     * 

* Note that only some conditions are supported. Conditions checking for things like piece position or orientation * should not be used, as instead those checks can be performed on the structure's placement itself. */ private static Optional getStartPiece( class_6880 startPoolHolder, Optional startJigsawNameOptional, class_2338 locatePos, class_3485 structureTemplateManager, class_5819 rand, class_9822 liquidSettings ) { class_3785 startPool = startPoolHolder.comp_349(); ObjectArrayList> candidatePoolElements = new ObjectArrayList<>(((StructureTemplatePoolAccessor) startPool).getRawTemplates()); // Shuffle our candidate pool elements class_156.method_43028(candidatePoolElements, rand); // Get a random orientation for starting piece class_2470 rotation = class_2470.method_16548(rand); // Sum of weights in all pieces in the pool. // When choosing a piece, we will remove its weight from this sum. int totalWeightSum = candidatePoolElements.stream().mapToInt(Pair::getSecond).reduce(0, Integer::sum); while (candidatePoolElements.size() > 0 && totalWeightSum > 0) { Pair chosenPoolElementPair = null; // First, check for any priority pieces for (Pair candidatePiecePair : candidatePoolElements) { class_3784 candidatePiece = candidatePiecePair.getFirst(); if (candidatePiece instanceof YungJigsawPoolElement yungElement && yungElement.isPriorityPiece()) { chosenPoolElementPair = candidatePiecePair; break; } } // Randomly choose piece if priority piece wasn't selected if (chosenPoolElementPair == null) { // Random weight used to choose random piece from the pool of candidates int chosenWeight = rand.method_43048(totalWeightSum) + 1; // Randomly choose a candidate piece for (Pair candidate : candidatePoolElements) { chosenWeight -= candidate.getSecond(); if (chosenWeight <= 0) { chosenPoolElementPair = candidate; break; } } } // Extract data from the chosen piece pair. class_3784 chosenPoolElement = chosenPoolElementPair.getFirst(); int chosenPieceWeight = chosenPoolElementPair.getSecond(); if (chosenPoolElement == class_3777.field_16663) { return Optional.empty(); } class_2338 anchorPos; if (startJigsawNameOptional.isPresent()) { class_2960 name = startJigsawNameOptional.get(); Optional optional = getPosOfJigsawBlockWithName(chosenPoolElement, name, locatePos, rotation, structureTemplateManager, rand); if (optional.isEmpty()) { YungsApiCommon.LOGGER.error("No starting jigsaw with Name {} found in start pool {}", name, startPoolHolder.method_40230() .map(pool -> pool.method_29177().toString()) .orElse("")); return Optional.empty(); } anchorPos = optional.get(); } else { anchorPos = locatePos; } // We adjust the starting position such that, if a named start jigsaw is being used (i.e. an anchor), // then the anchor's position will be located at the original starting position. class_2382 startingPosOffset = anchorPos.method_10059(locatePos); class_2338 adjustedStartPos = locatePos.method_10059(startingPosOffset); // Validate conditions for this piece, if applicable if (chosenPoolElement instanceof YungJigsawPoolElement yungElement) { StructureContext ctx = new StructureContext.Builder() .structureTemplateManager(structureTemplateManager) .pos(adjustedStartPos) .rotation(rotation) .depth(0) .random(rand) .build(); if (!yungElement.passesConditions(ctx)) { totalWeightSum -= chosenPieceWeight; candidatePoolElements.remove(chosenPoolElementPair); continue; // Abort this piece if it doesn't pass conditions check } } // Instantiate piece return Optional.of(new class_3790( structureTemplateManager, chosenPoolElement, adjustedStartPos, chosenPoolElement.method_19308(), rotation, chosenPoolElement.method_16628(structureTemplateManager, adjustedStartPos, rotation), liquidSettings )); } return Optional.empty(); } /** * Returns a jigsaw block with the specified name in the StructurePoolElement. * If no such jigsaw block is found, returns an empty Optional. *

* This is used for starting pieces, when you want /locate to point to a position other than the * corner of the start piece, such as the center of ancient cities. */ private static Optional getPosOfJigsawBlockWithName( class_3784 structurePoolElement, class_2960 name, class_2338 startPos, class_2470 rotation, class_3485 structureTemplateManager, class_5819 rand ) { // Wrap in try-catch because for some reason, getShuffledJigsawBlocks rarely throws a ConcurrentModificationException. // We'd rather just ignore the anchor jigsaw block than crash the game. try { List shuffledJigsawBlocks = structurePoolElement.method_16627(structureTemplateManager, startPos, rotation, rand); for (class_3499.class_3501 jigsawBlockInfo : shuffledJigsawBlocks) { class_2960 jigsawBlockName = class_2960.method_12829(jigsawBlockInfo.comp_1343().method_10558("name")); if (name.equals(jigsawBlockName)) { return Optional.of(jigsawBlockInfo.comp_1341()); } } } catch (ConcurrentModificationException e) { YungsApiCommon.LOGGER.error("Encountered unexpected ConcurrentModException while trying to get jigsaw block with name {} from structure pool element {}", name, structurePoolElement); YungsApiCommon.LOGGER.error("Ignoring - the structure will still generate, but /locate will not point to the structure's anchor block."); return Optional.empty(); } return Optional.empty(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy