File size: 15,128 Bytes
d46f4a3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
package net.minecraft.gametest.framework;

import com.mojang.logging.LogUtils;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import net.minecraft.commands.arguments.blocks.BlockInput;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.entity.CommandBlockEntity;
import net.minecraft.world.level.block.entity.StructureBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.StructureMode;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger;

public class StructureUtils {
    private static final Logger LOGGER = LogUtils.getLogger();
    public static final int DEFAULT_Y_SEARCH_RADIUS = 10;
    public static final String DEFAULT_TEST_STRUCTURES_DIR = "gameteststructures";
    public static String testStructuresDir = "gameteststructures";

    public static Rotation getRotationForRotationSteps(int p_127836_) {
        switch (p_127836_) {
            case 0:
                return Rotation.NONE;
            case 1:
                return Rotation.CLOCKWISE_90;
            case 2:
                return Rotation.CLOCKWISE_180;
            case 3:
                return Rotation.COUNTERCLOCKWISE_90;
            default:
                throw new IllegalArgumentException("rotationSteps must be a value from 0-3. Got value " + p_127836_);
        }
    }

    public static int getRotationStepsForRotation(Rotation p_177752_) {
        switch (p_177752_) {
            case NONE:
                return 0;
            case CLOCKWISE_90:
                return 1;
            case CLOCKWISE_180:
                return 2;
            case COUNTERCLOCKWISE_90:
                return 3;
            default:
                throw new IllegalArgumentException("Unknown rotation value, don't know how many steps it represents: " + p_177752_);
        }
    }

    public static AABB getStructureBounds(StructureBlockEntity p_127848_) {
        return AABB.of(getStructureBoundingBox(p_127848_));
    }

    public static BoundingBox getStructureBoundingBox(StructureBlockEntity p_127905_) {
        BlockPos blockpos = getStructureOrigin(p_127905_);
        BlockPos blockpos1 = getTransformedFarCorner(blockpos, p_127905_.getStructureSize(), p_127905_.getRotation());
        return BoundingBox.fromCorners(blockpos, blockpos1);
    }

    public static BlockPos getStructureOrigin(StructureBlockEntity p_311311_) {
        return p_311311_.getBlockPos().offset(p_311311_.getStructurePos());
    }

    public static void addCommandBlockAndButtonToStartTest(BlockPos p_127876_, BlockPos p_127877_, Rotation p_127878_, ServerLevel p_127879_) {
        BlockPos blockpos = StructureTemplate.transform(p_127876_.offset(p_127877_), Mirror.NONE, p_127878_, p_127876_);
        p_127879_.setBlockAndUpdate(blockpos, Blocks.COMMAND_BLOCK.defaultBlockState());
        CommandBlockEntity commandblockentity = (CommandBlockEntity)p_127879_.getBlockEntity(blockpos);
        commandblockentity.getCommandBlock().setCommand("test runclosest");
        BlockPos blockpos1 = StructureTemplate.transform(blockpos.offset(0, 0, -1), Mirror.NONE, p_127878_, blockpos);
        p_127879_.setBlockAndUpdate(blockpos1, Blocks.STONE_BUTTON.defaultBlockState().rotate(p_127878_));
    }

    public static void createNewEmptyStructureBlock(String p_177765_, BlockPos p_177766_, Vec3i p_177767_, Rotation p_177768_, ServerLevel p_177769_) {
        BoundingBox boundingbox = getStructureBoundingBox(p_177766_.above(), p_177767_, p_177768_);
        clearSpaceForStructure(boundingbox, p_177769_);
        p_177769_.setBlockAndUpdate(p_177766_, Blocks.STRUCTURE_BLOCK.defaultBlockState());
        StructureBlockEntity structureblockentity = (StructureBlockEntity)p_177769_.getBlockEntity(p_177766_);
        structureblockentity.setIgnoreEntities(false);
        structureblockentity.setStructureName(ResourceLocation.parse(p_177765_));
        structureblockentity.setMetaData(p_177765_);
        structureblockentity.setStructureSize(p_177767_);
        structureblockentity.setMode(StructureMode.SAVE);
        structureblockentity.setShowBoundingBox(true);
    }

    public static BlockPos getStartCorner(GameTestInfo p_364513_, BlockPos p_364702_, Rotation p_360789_, ServerLevel p_360785_) {
        Vec3i vec3i = p_360785_.getStructureManager()
            .get(ResourceLocation.parse(p_364513_.getStructureName()))
            .orElseThrow(() -> new IllegalStateException("Missing test structure: " + p_364513_.getStructureName()))
            .getSize();
        BlockPos blockpos;
        if (p_360789_ == Rotation.NONE) {
            blockpos = p_364702_;
        } else if (p_360789_ == Rotation.CLOCKWISE_90) {
            blockpos = p_364702_.offset(vec3i.getZ() - 1, 0, 0);
        } else if (p_360789_ == Rotation.CLOCKWISE_180) {
            blockpos = p_364702_.offset(vec3i.getX() - 1, 0, vec3i.getZ() - 1);
        } else {
            if (p_360789_ != Rotation.COUNTERCLOCKWISE_90) {
                throw new IllegalArgumentException("Invalid rotation: " + p_360789_);
            }

            blockpos = p_364702_.offset(0, 0, vec3i.getX() - 1);
        }

        return blockpos;
    }

    public static StructureBlockEntity prepareTestStructure(GameTestInfo p_311701_, BlockPos p_311042_, Rotation p_310584_, ServerLevel p_312330_) {
        Vec3i vec3i = p_312330_.getStructureManager()
            .get(ResourceLocation.parse(p_311701_.getStructureName()))
            .orElseThrow(() -> new IllegalStateException("Missing test structure: " + p_311701_.getStructureName()))
            .getSize();
        BoundingBox boundingbox = getStructureBoundingBox(p_311042_, vec3i, p_310584_);
        BlockPos blockpos = getStartCorner(p_311701_, p_311042_, p_310584_, p_312330_);
        forceLoadChunks(boundingbox, p_312330_);
        clearSpaceForStructure(boundingbox, p_312330_);
        return createStructureBlock(p_311701_, blockpos.below(), p_310584_, p_312330_);
    }

    public static void encaseStructure(AABB p_330422_, ServerLevel p_331249_, boolean p_328180_) {
        BlockPos blockpos = BlockPos.containing(p_330422_.minX, p_330422_.minY, p_330422_.minZ).offset(-1, 0, -1);
        BlockPos blockpos1 = BlockPos.containing(p_330422_.maxX, p_330422_.maxY, p_330422_.maxZ);
        BlockPos.betweenClosedStream(blockpos, blockpos1)
            .forEach(
                p_325964_ -> {
                    boolean flag = p_325964_.getX() == blockpos.getX()
                        || p_325964_.getX() == blockpos1.getX()
                        || p_325964_.getZ() == blockpos.getZ()
                        || p_325964_.getZ() == blockpos1.getZ();
                    boolean flag1 = p_325964_.getY() == blockpos1.getY();
                    if (flag || flag1 && p_328180_) {
                        p_331249_.setBlockAndUpdate(p_325964_, Blocks.BARRIER.defaultBlockState());
                    }
                }
            );
    }

    public static void removeBarriers(AABB p_336061_, ServerLevel p_334551_) {
        BlockPos blockpos = BlockPos.containing(p_336061_.minX, p_336061_.minY, p_336061_.minZ).offset(-1, 0, -1);
        BlockPos blockpos1 = BlockPos.containing(p_336061_.maxX, p_336061_.maxY, p_336061_.maxZ);
        BlockPos.betweenClosedStream(blockpos, blockpos1)
            .forEach(
                p_325970_ -> {
                    boolean flag = p_325970_.getX() == blockpos.getX()
                        || p_325970_.getX() == blockpos1.getX()
                        || p_325970_.getZ() == blockpos.getZ()
                        || p_325970_.getZ() == blockpos1.getZ();
                    boolean flag1 = p_325970_.getY() == blockpos1.getY();
                    if (p_334551_.getBlockState(p_325970_).is(Blocks.BARRIER) && (flag || flag1)) {
                        p_334551_.setBlockAndUpdate(p_325970_, Blocks.AIR.defaultBlockState());
                    }
                }
            );
    }

    private static void forceLoadChunks(BoundingBox p_312219_, ServerLevel p_127859_) {
        p_312219_.intersectingChunks().forEach(p_308541_ -> p_127859_.setChunkForced(p_308541_.x, p_308541_.z, true));
    }

    public static void clearSpaceForStructure(BoundingBox p_127850_, ServerLevel p_127852_) {
        int i = p_127850_.minY() - 1;
        BoundingBox boundingbox = new BoundingBox(
            p_127850_.minX() - 2,
            p_127850_.minY() - 3,
            p_127850_.minZ() - 3,
            p_127850_.maxX() + 3,
            p_127850_.maxY() + 20,
            p_127850_.maxZ() + 3
        );
        BlockPos.betweenClosedStream(boundingbox).forEach(p_177748_ -> clearBlock(i, p_177748_, p_127852_));
        p_127852_.getBlockTicks().clearArea(boundingbox);
        p_127852_.clearBlockEvents(boundingbox);
        AABB aabb = AABB.of(boundingbox);
        List<Entity> list = p_127852_.getEntitiesOfClass(Entity.class, aabb, p_177750_ -> !(p_177750_ instanceof Player));
        list.forEach(Entity::discard);
    }

    public static BlockPos getTransformedFarCorner(BlockPos p_310098_, Vec3i p_312132_, Rotation p_309587_) {
        BlockPos blockpos = p_310098_.offset(p_312132_).offset(-1, -1, -1);
        return StructureTemplate.transform(blockpos, Mirror.NONE, p_309587_, p_310098_);
    }

    public static BoundingBox getStructureBoundingBox(BlockPos p_177761_, Vec3i p_177762_, Rotation p_177763_) {
        BlockPos blockpos = getTransformedFarCorner(p_177761_, p_177762_, p_177763_);
        BoundingBox boundingbox = BoundingBox.fromCorners(p_177761_, blockpos);
        int i = Math.min(boundingbox.minX(), boundingbox.maxX());
        int j = Math.min(boundingbox.minZ(), boundingbox.maxZ());
        return boundingbox.move(p_177761_.getX() - i, 0, p_177761_.getZ() - j);
    }

    public static Optional<BlockPos> findStructureBlockContainingPos(BlockPos p_127854_, int p_127855_, ServerLevel p_127856_) {
        return findStructureBlocks(p_127854_, p_127855_, p_127856_).filter(p_177756_ -> doesStructureContain(p_177756_, p_127854_, p_127856_)).findFirst();
    }

    public static Optional<BlockPos> findNearestStructureBlock(BlockPos p_127907_, int p_127908_, ServerLevel p_127909_) {
        Comparator<BlockPos> comparator = Comparator.comparingInt(p_177759_ -> p_177759_.distManhattan(p_127907_));
        return findStructureBlocks(p_127907_, p_127908_, p_127909_).min(comparator);
    }

    public static Stream<BlockPos> findStructureByTestFunction(BlockPos p_333272_, int p_332388_, ServerLevel p_333747_, String p_332891_) {
        return findStructureBlocks(p_333272_, p_332388_, p_333747_)
            .map(p_325972_ -> (StructureBlockEntity)p_333747_.getBlockEntity(p_325972_))
            .filter(Objects::nonNull)
            .filter(p_325954_ -> Objects.equals(p_325954_.getStructureName(), p_332891_))
            .map(BlockEntity::getBlockPos)
            .map(BlockPos::immutable);
    }

    public static Stream<BlockPos> findStructureBlocks(BlockPos p_127911_, int p_127912_, ServerLevel p_127913_) {
        BoundingBox boundingbox = getBoundingBoxAtGround(p_127911_, p_127912_, p_127913_);
        return BlockPos.betweenClosedStream(boundingbox).filter(p_325959_ -> p_127913_.getBlockState(p_325959_).is(Blocks.STRUCTURE_BLOCK)).map(BlockPos::immutable);
    }

    private static StructureBlockEntity createStructureBlock(GameTestInfo p_309598_, BlockPos p_127892_, Rotation p_127893_, ServerLevel p_127894_) {
        p_127894_.setBlockAndUpdate(p_127892_, Blocks.STRUCTURE_BLOCK.defaultBlockState());
        StructureBlockEntity structureblockentity = (StructureBlockEntity)p_127894_.getBlockEntity(p_127892_);
        structureblockentity.setMode(StructureMode.LOAD);
        structureblockentity.setRotation(p_127893_);
        structureblockentity.setIgnoreEntities(false);
        structureblockentity.setStructureName(ResourceLocation.parse(p_309598_.getStructureName()));
        structureblockentity.setMetaData(p_309598_.getTestName());
        if (!structureblockentity.loadStructureInfo(p_127894_)) {
            throw new RuntimeException("Failed to load structure info for test: " + p_309598_.getTestName() + ". Structure name: " + p_309598_.getStructureName());
        } else {
            return structureblockentity;
        }
    }

    private static BoundingBox getBoundingBoxAtGround(BlockPos p_329849_, int p_332427_, ServerLevel p_328726_) {
        BlockPos blockpos = BlockPos.containing(
            (double)p_329849_.getX(), (double)p_328726_.getHeightmapPos(Heightmap.Types.WORLD_SURFACE, p_329849_).getY(), (double)p_329849_.getZ()
        );
        return new BoundingBox(blockpos).inflatedBy(p_332427_, 10, p_332427_);
    }

    public static Stream<BlockPos> lookedAtStructureBlockPos(BlockPos p_333762_, Entity p_333965_, ServerLevel p_336162_) {
        int i = 200;
        Vec3 vec3 = p_333965_.getEyePosition();
        Vec3 vec31 = vec3.add(p_333965_.getLookAngle().scale(200.0));
        return findStructureBlocks(p_333762_, 200, p_336162_)
            .map(p_325966_ -> p_336162_.getBlockEntity(p_325966_, BlockEntityType.STRUCTURE_BLOCK))
            .flatMap(Optional::stream)
            .filter(p_325957_ -> getStructureBounds(p_325957_).clip(vec3, vec31).isPresent())
            .map(BlockEntity::getBlockPos)
            .sorted(Comparator.comparing(p_333762_::distSqr))
            .limit(1L);
    }

    private static void clearBlock(int p_127842_, BlockPos p_127843_, ServerLevel p_127844_) {
        BlockState blockstate;
        if (p_127843_.getY() < p_127842_) {
            blockstate = Blocks.STONE.defaultBlockState();
        } else {
            blockstate = Blocks.AIR.defaultBlockState();
        }

        BlockInput blockinput = new BlockInput(blockstate, Collections.emptySet(), null);
        blockinput.place(p_127844_, p_127843_, 2);
        p_127844_.blockUpdated(p_127843_, blockstate.getBlock());
    }

    private static boolean doesStructureContain(BlockPos p_127868_, BlockPos p_127869_, ServerLevel p_127870_) {
        StructureBlockEntity structureblockentity = (StructureBlockEntity)p_127870_.getBlockEntity(p_127868_);
        return getStructureBoundingBox(structureblockentity).isInside(p_127869_);
    }
}