2021-05-17 03:02:24 +08:00
|
|
|
package com.gtnewhorizon.structurelib.structure;
|
|
|
|
|
|
2022-08-12 12:25:03 +08:00
|
|
|
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.ignoreBlockUnloaded;
|
|
|
|
|
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.skipBlockUnloaded;
|
2022-08-08 17:40:12 +08:00
|
|
|
|
2025-10-28 12:34:01 -04:00
|
|
|
import java.util.List;
|
2022-08-30 23:27:18 +08:00
|
|
|
import java.util.function.Function;
|
2023-01-30 12:52:27 +00:00
|
|
|
|
2025-10-28 12:34:01 -04:00
|
|
|
import javax.annotation.Nonnull;
|
|
|
|
|
|
2022-09-11 02:54:11 +08:00
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
2022-08-08 17:40:12 +08:00
|
|
|
import net.minecraft.entity.player.EntityPlayerMP;
|
2021-05-17 03:02:24 +08:00
|
|
|
import net.minecraft.item.ItemStack;
|
|
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
|
|
|
|
|
import com.gtnewhorizon.structurelib.StructureLib;
|
2022-08-30 23:27:18 +08:00
|
|
|
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
2024-12-14 13:13:34 -05:00
|
|
|
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
2022-09-11 02:54:11 +08:00
|
|
|
import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
|
2021-05-17 03:02:24 +08:00
|
|
|
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
2025-10-28 12:34:01 -04:00
|
|
|
import com.gtnewhorizon.structurelib.coords.Position;
|
|
|
|
|
import com.gtnewhorizon.structurelib.coords.StructureDefinitionCoords;
|
2023-01-30 12:52:27 +00:00
|
|
|
|
2022-08-30 23:27:18 +08:00
|
|
|
/**
|
|
|
|
|
* This is the structure definition of your multi. You will have one of these for each multi.
|
|
|
|
|
*
|
|
|
|
|
* <h2>Cache the instances of this class</h2>
|
|
|
|
|
* <p>
|
|
|
|
|
* You will construct this definition once per multi, either at class load or at first call to your variant of
|
|
|
|
|
* {@code getStructureDefinition()}. You can use a {@link ClassValue ClassValue<IStructureDefinition<?>>} if you
|
|
|
|
|
* have a template for subclass. You can also use {@link StructureUtility#defer(Function) defer()} or its overloads for
|
|
|
|
|
* simpler cases, but it is slightly less performant as it will allocate new objects on each structure check, whereas
|
|
|
|
|
* {@link ClassValue} will allocate once and cache it onwards.
|
|
|
|
|
* <p>
|
|
|
|
|
* <h2>Constructing</h2>
|
|
|
|
|
* <p>
|
|
|
|
|
* {@linkplain IStructureDefinition} is constructed using {@link IStructureDefinition#builder()}
|
|
|
|
|
* <p>
|
|
|
|
|
* Builder has two main methods:
|
|
|
|
|
* <ul>
|
|
|
|
|
* <li>{@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addShape(String, String[][])
|
|
|
|
|
* addShape()} is a 2d string array describing the layout of structure. You can optionally use
|
|
|
|
|
* `StructureUtility#transpose()` to transpose the array to make the structure look nicer in source code.
|
|
|
|
|
* <li>{@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addElement(Character, IStructureElement)
|
|
|
|
|
* addElement()}. It takes a char identifier (mapped to a char in any of
|
|
|
|
|
* {@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addShape(String, String[][]) addShape()}
|
|
|
|
|
* calls) and a {@link IStructureElement}.
|
|
|
|
|
* </ul>
|
|
|
|
|
* <h2>Position A, B and C</h2>
|
|
|
|
|
*
|
|
|
|
|
* Imagine you stand in front of the controller, with controller facing towards you not rotated or flipped.
|
|
|
|
|
* <ul>
|
|
|
|
|
* <li>The "A" position would be the number of blocks on the left side of the controller, not counting controller
|
|
|
|
|
* itself.</li>
|
|
|
|
|
* <li>The "B" position would be the number of blocks on the top side of the controller, not counting controller
|
|
|
|
|
* itself.</li>
|
|
|
|
|
* <li>The "C" position would be the number of blocks between you and controller, not counting controller itself.</li>
|
|
|
|
|
* </ul>
|
2024-12-14 13:13:34 -05:00
|
|
|
*
|
2022-08-30 23:27:18 +08:00
|
|
|
* @param <T> Type of the context object. Usually this will be the multiblock controller.
|
|
|
|
|
*/
|
2021-05-17 03:02:24 +08:00
|
|
|
public interface IStructureDefinition<T> {
|
2023-01-30 12:52:27 +00:00
|
|
|
|
2022-07-08 17:14:18 +08:00
|
|
|
/**
|
|
|
|
|
* Used internally
|
|
|
|
|
* <p>
|
|
|
|
|
* Might, but is not required, to throw {@link java.util.NoSuchElementException} if the given structure piece is not
|
|
|
|
|
* found.
|
|
|
|
|
*
|
|
|
|
|
* @param name same name as for other methods here
|
|
|
|
|
* @return the array of elements to process
|
|
|
|
|
* @throws java.util.NoSuchElementException if the given structure piece is not found and the moon phase perfectly
|
|
|
|
|
* matches
|
|
|
|
|
*/
|
|
|
|
|
IStructureElement<T>[] getStructureFor(String name);
|
|
|
|
|
|
2022-09-11 02:54:11 +08:00
|
|
|
boolean isContainedInStructure(String name, int offsetA, int offsetB, int offsetC);
|
|
|
|
|
|
2022-08-30 23:27:18 +08:00
|
|
|
/**
|
|
|
|
|
* Run a structure check.
|
2024-12-14 13:13:34 -05:00
|
|
|
*
|
2022-08-30 23:27:18 +08:00
|
|
|
* @param object context object. usually multiblock controller.
|
|
|
|
|
* @param piece the structure piece's string identifier.
|
|
|
|
|
* @param world the world object this check takes place in.
|
|
|
|
|
* @param extendedFacing the current structure's orientation.
|
|
|
|
|
* @param basePositionX X location of the structure
|
|
|
|
|
* @param basePositionY Y location of the structure
|
|
|
|
|
* @param basePositionZ Z location of the structure
|
|
|
|
|
* @param basePositionA see class javadoc
|
|
|
|
|
* @param basePositionB see class javadoc
|
|
|
|
|
* @param basePositionC see class javadoc
|
|
|
|
|
* @param forceCheckAllBlocks check all location even if chunk not currently loaded.
|
|
|
|
|
* @return true if successful, false otherwise
|
|
|
|
|
*/
|
2022-08-08 17:40:12 +08:00
|
|
|
default boolean check(T object, String piece, World world, ExtendedFacing extendedFacing, int basePositionX,
|
|
|
|
|
int basePositionY, int basePositionZ, int basePositionA, int basePositionB, int basePositionC,
|
|
|
|
|
boolean forceCheckAllBlocks) {
|
|
|
|
|
return iterate(
|
|
|
|
|
object,
|
|
|
|
|
null,
|
|
|
|
|
getStructureFor(piece),
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
|
|
|
|
false,
|
|
|
|
|
forceCheckAllBlocks);
|
2022-07-08 17:14:18 +08:00
|
|
|
}
|
|
|
|
|
|
2022-08-30 23:27:18 +08:00
|
|
|
/**
|
|
|
|
|
* Spawn hint particles. Should not be called on server side.
|
2024-12-14 13:13:34 -05:00
|
|
|
*
|
2022-08-30 23:27:18 +08:00
|
|
|
* @param object context object. usually multiblock controller.
|
|
|
|
|
* @param piece the structure piece's string identifier.
|
|
|
|
|
* @param world the world object this check takes place in.
|
|
|
|
|
* @param extendedFacing the current structure's orientation.
|
|
|
|
|
* @param basePositionX X location of the structure
|
|
|
|
|
* @param basePositionY Y location of the structure
|
|
|
|
|
* @param basePositionZ Z location of the structure
|
|
|
|
|
* @param basePositionA see class javadoc
|
|
|
|
|
* @param basePositionB see class javadoc
|
|
|
|
|
* @param basePositionC see class javadoc
|
|
|
|
|
* @return true if successful, false otherwise
|
|
|
|
|
*/
|
2022-08-08 17:40:12 +08:00
|
|
|
default boolean hints(T object, ItemStack trigger, String piece, World world, ExtendedFacing extendedFacing,
|
|
|
|
|
int basePositionX, int basePositionY, int basePositionZ, int basePositionA, int basePositionB,
|
|
|
|
|
int basePositionC) {
|
|
|
|
|
return iterate(
|
|
|
|
|
object,
|
|
|
|
|
trigger,
|
|
|
|
|
getStructureFor(piece),
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
|
|
|
|
true,
|
|
|
|
|
null);
|
2022-07-08 17:14:18 +08:00
|
|
|
}
|
|
|
|
|
|
2022-08-30 23:27:18 +08:00
|
|
|
/**
|
2022-09-06 16:34:46 +08:00
|
|
|
* Build the multi in creative mode on a best-effort basis. Does not guarantee the structure is correct after a
|
2022-08-30 23:27:18 +08:00
|
|
|
* successful call.
|
|
|
|
|
*
|
|
|
|
|
* @param object context object. usually multiblock controller.
|
|
|
|
|
* @param trigger The trigger item that contains channel data.
|
|
|
|
|
* @param piece the structure piece's string identifier.
|
|
|
|
|
* @param world the world object this check takes place in.
|
|
|
|
|
* @param extendedFacing the current structure's orientation.
|
|
|
|
|
* @param basePositionX X location of the structure
|
|
|
|
|
* @param basePositionY Y location of the structure
|
|
|
|
|
* @param basePositionZ Z location of the structure
|
|
|
|
|
* @param basePositionA see class javadoc
|
|
|
|
|
* @param basePositionB see class javadoc
|
|
|
|
|
* @param basePositionC see class javadoc
|
|
|
|
|
* @return true if sucessful, false otherwise
|
|
|
|
|
*/
|
2022-08-08 17:40:12 +08:00
|
|
|
default boolean build(T object, ItemStack trigger, String piece, World world, ExtendedFacing extendedFacing,
|
|
|
|
|
int basePositionX, int basePositionY, int basePositionZ, int basePositionA, int basePositionB,
|
|
|
|
|
int basePositionC) {
|
|
|
|
|
return iterate(
|
|
|
|
|
object,
|
|
|
|
|
trigger,
|
|
|
|
|
getStructureFor(piece),
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
|
|
|
|
false,
|
|
|
|
|
null);
|
2022-07-08 17:14:18 +08:00
|
|
|
}
|
|
|
|
|
|
2022-08-30 23:27:18 +08:00
|
|
|
/**
|
|
|
|
|
* Call {@link #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)} if
|
|
|
|
|
* {@code hintsOnly}, call
|
|
|
|
|
* {@link #hints(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)} otherwise.
|
|
|
|
|
*
|
|
|
|
|
* @param object context object. usually multiblock controller.
|
|
|
|
|
* @param trigger The trigger item that contains channel data.
|
|
|
|
|
* @param piece the structure piece's string identifier.
|
|
|
|
|
* @param world the world object this check takes place in.
|
|
|
|
|
* @param extendedFacing the current structure's orientation.
|
|
|
|
|
* @param basePositionX X location of the structure
|
|
|
|
|
* @param basePositionY Y location of the structure
|
|
|
|
|
* @param basePositionZ Z location of the structure
|
|
|
|
|
* @param basePositionA see class javadoc
|
|
|
|
|
* @param basePositionB see class javadoc
|
|
|
|
|
* @param basePositionC see class javadoc
|
|
|
|
|
* @param hintsOnly whether to spawn hints or do creative build.
|
|
|
|
|
* @return true if sucessful, false otherwise
|
|
|
|
|
* @see #hints(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)
|
|
|
|
|
* @see #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)
|
|
|
|
|
*/
|
2022-08-08 17:40:12 +08:00
|
|
|
default boolean buildOrHints(T object, ItemStack trigger, String piece, World world, ExtendedFacing extendedFacing,
|
|
|
|
|
int basePositionX, int basePositionY, int basePositionZ, int basePositionA, int basePositionB,
|
|
|
|
|
int basePositionC, boolean hintsOnly) {
|
|
|
|
|
return iterate(
|
|
|
|
|
object,
|
|
|
|
|
trigger,
|
|
|
|
|
getStructureFor(piece),
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
|
|
|
|
hintsOnly,
|
|
|
|
|
null);
|
2022-07-08 17:14:18 +08:00
|
|
|
}
|
|
|
|
|
|
2022-08-08 17:40:12 +08:00
|
|
|
/**
|
2022-08-30 23:27:18 +08:00
|
|
|
* Cause a survival build.
|
|
|
|
|
*
|
|
|
|
|
* @param object context object. usually multiblock controller.
|
|
|
|
|
* @param trigger The trigger item that contains channel data.
|
|
|
|
|
* @param piece the structure piece's string identifier.
|
|
|
|
|
* @param world the world object this check takes place in.
|
|
|
|
|
* @param extendedFacing the current structure's orientation.
|
|
|
|
|
* @param basePositionX X location of the structure
|
|
|
|
|
* @param basePositionY Y location of the structure
|
|
|
|
|
* @param basePositionZ Z location of the structure
|
|
|
|
|
* @param basePositionA see class javadoc
|
|
|
|
|
* @param basePositionB see class javadoc
|
|
|
|
|
* @param basePositionC see class javadoc
|
2022-08-08 17:40:12 +08:00
|
|
|
* @param elementBudget build up to this many elements
|
|
|
|
|
* @param source from where to drain resource
|
|
|
|
|
* @param actor source of action
|
|
|
|
|
* @param check whether {@link IStructureElement#check(Object, World, int, int, int)} should be called if
|
|
|
|
|
* anything would be placed. use with caution. if in doubt, call
|
|
|
|
|
* {@link #check(Object, String, World, ExtendedFacing, int, int, int, int, int, int, boolean)}
|
|
|
|
|
* after this call and set this parameter to false
|
|
|
|
|
* @return number of elements built, or -1 if structure done
|
|
|
|
|
* @see #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)
|
|
|
|
|
*/
|
2022-09-11 02:54:11 +08:00
|
|
|
@Deprecated
|
2022-08-08 17:40:12 +08:00
|
|
|
default int survivalBuild(T object, ItemStack trigger, String piece, World world, ExtendedFacing extendedFacing,
|
|
|
|
|
int basePositionX, int basePositionY, int basePositionZ, int basePositionA, int basePositionB,
|
|
|
|
|
int basePositionC, int elementBudget, IItemSource source, EntityPlayerMP actor, boolean check) {
|
2022-09-11 02:54:11 +08:00
|
|
|
EntityPlayer realActor;
|
|
|
|
|
if (actor == null) {
|
|
|
|
|
realActor = ISurvivalConstructable.__get_player();
|
|
|
|
|
if (realActor == null) throw new IllegalArgumentException();
|
|
|
|
|
} else {
|
|
|
|
|
realActor = actor;
|
|
|
|
|
}
|
|
|
|
|
return survivalBuild(
|
|
|
|
|
object,
|
|
|
|
|
trigger,
|
|
|
|
|
piece,
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
|
|
|
|
elementBudget,
|
|
|
|
|
ISurvivalBuildEnvironment.create(source, realActor),
|
|
|
|
|
check);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Cause a survival build.
|
|
|
|
|
*
|
|
|
|
|
* @param object context object. usually multiblock controller.
|
|
|
|
|
* @param trigger The trigger item that contains channel data.
|
|
|
|
|
* @param piece the structure piece's string identifier.
|
|
|
|
|
* @param world the world object this check takes place in.
|
|
|
|
|
* @param extendedFacing the current structure's orientation.
|
|
|
|
|
* @param basePositionX X location of the structure
|
|
|
|
|
* @param basePositionY Y location of the structure
|
|
|
|
|
* @param basePositionZ Z location of the structure
|
|
|
|
|
* @param basePositionA see class javadoc
|
|
|
|
|
* @param basePositionB see class javadoc
|
|
|
|
|
* @param basePositionC see class javadoc
|
|
|
|
|
* @param elementBudget build up to this many elements
|
|
|
|
|
* @param env build environment.
|
|
|
|
|
* @param check whether {@link IStructureElement#check(Object, World, int, int, int)} should be called if
|
|
|
|
|
* anything would be placed. use with caution. if in doubt, call
|
|
|
|
|
* {@link IStructureDefinition#check(Object, String, World, ExtendedFacing, int, int, int, int, int, int, boolean)}
|
|
|
|
|
* after this call and set this parameter to false
|
|
|
|
|
* @return number of elements built, or -1 if structure done
|
|
|
|
|
* @see #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)
|
|
|
|
|
*/
|
|
|
|
|
default int survivalBuild(T object, ItemStack trigger, String piece, World world, ExtendedFacing extendedFacing,
|
|
|
|
|
int basePositionX, int basePositionY, int basePositionZ, int basePositionA, int basePositionB,
|
|
|
|
|
int basePositionC, int elementBudget, ISurvivalBuildEnvironment env, boolean check) {
|
|
|
|
|
SurvivalBuildStructureWalker<T> walker = new SurvivalBuildStructureWalker<>(
|
|
|
|
|
object,
|
|
|
|
|
trigger,
|
|
|
|
|
elementBudget,
|
|
|
|
|
env,
|
|
|
|
|
this,
|
|
|
|
|
piece,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
new int[] { basePositionA, basePositionB, basePositionC },
|
|
|
|
|
check);
|
2022-08-08 17:40:12 +08:00
|
|
|
StructureUtility.iterateV2(
|
|
|
|
|
getStructureFor(piece),
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
|
|
|
|
walker,
|
|
|
|
|
"survivalBuild");
|
|
|
|
|
return walker.getBuilt();
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-28 00:52:40 -04:00
|
|
|
default void iterate(String piece, World world, ExtendedFacing extendedFacing, int basePositionX, int basePositionY,
|
|
|
|
|
int basePositionZ, int basePositionA, int basePositionB, int basePositionC, IStructureWalker<T> predicate) {
|
|
|
|
|
StructureUtility.iterateV2(
|
|
|
|
|
getStructureFor(piece),
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
|
|
|
|
predicate,
|
|
|
|
|
"customIterate");
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-28 12:34:01 -04:00
|
|
|
/**
|
|
|
|
|
* Gets the controller position for a piece. Controller positions are denoted by a tilde.
|
|
|
|
|
*
|
|
|
|
|
* @param piece The piece name
|
|
|
|
|
* @return The controller position, or null if it doesn't exist for the given piece
|
|
|
|
|
*/
|
|
|
|
|
Position<StructureDefinitionCoords> getControllerPosition(String piece);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the coordinate system for a piece. This is used to translate structure definition coordinates into structure
|
|
|
|
|
* relative coordinates.
|
|
|
|
|
*
|
|
|
|
|
* @param piece The piece
|
|
|
|
|
* @return The coordinate system
|
|
|
|
|
* @throws IllegalArgumentException When the piece does not exist
|
|
|
|
|
*/
|
|
|
|
|
StructureDefinitionCoords getCoordinateSystem(String piece);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets a socket from a piece.
|
|
|
|
|
*
|
|
|
|
|
* @param piece The piece name
|
|
|
|
|
* @param socket The socket character
|
|
|
|
|
* @return The socket's position
|
|
|
|
|
* @throws IllegalArgumentException When the piece does not exist
|
|
|
|
|
* @throws IllegalArgumentException When the socket does not exist
|
|
|
|
|
* @throws IllegalStateException When more than one socket exists with this character
|
|
|
|
|
* @see StructureDefinition.Builder#addSocket(char, char)
|
|
|
|
|
*/
|
|
|
|
|
Position<StructureDefinitionCoords> getSocket(String piece, char socket);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets all sockets with a given character for a piece.
|
|
|
|
|
*
|
|
|
|
|
* @param piece The piece name
|
|
|
|
|
* @param socket The socket character
|
|
|
|
|
* @return The list of socket positions, or an empty list if the socket is not present
|
|
|
|
|
* @throws IllegalArgumentException When the piece does not exist
|
|
|
|
|
* @see StructureDefinition.Builder#addSocket(char, char)
|
|
|
|
|
*/
|
|
|
|
|
@Nonnull
|
|
|
|
|
List<Position<StructureDefinitionCoords>> getAllSockets(String piece, char socket);
|
|
|
|
|
|
2022-08-30 23:27:18 +08:00
|
|
|
/**
|
|
|
|
|
* Low level utility.
|
2024-12-14 13:13:34 -05:00
|
|
|
*
|
2022-08-30 23:27:18 +08:00
|
|
|
* @param object context object. usually multiblock controller.
|
|
|
|
|
* @param trigger The trigger item that contains channel data.
|
|
|
|
|
* @param elements the structure piece
|
|
|
|
|
* @param world the world object this check takes place in.
|
|
|
|
|
* @param extendedFacing the current structure's orientation.
|
|
|
|
|
* @param basePositionX X location of the structure
|
|
|
|
|
* @param basePositionY Y location of the structure
|
|
|
|
|
* @param basePositionZ Z location of the structure
|
|
|
|
|
* @param basePositionA see class javadoc
|
|
|
|
|
* @param basePositionB see class javadoc
|
|
|
|
|
* @param basePositionC see class javadoc
|
|
|
|
|
* @param hintsOnly whether to spawn hints or do creative build. no effect if
|
|
|
|
|
* {@code checkBlocksIfNotNullForceCheckAllIfTrue} is not null.
|
|
|
|
|
* @param checkBlocksIfNotNullForceCheckAllIfTrue creative build or spawn hints if null. Force check not loaded
|
|
|
|
|
* chunk if true. Check only loaded chunk is false.
|
|
|
|
|
* @return true if iteration completed successfully.
|
|
|
|
|
* @param <T> type of context object.
|
|
|
|
|
*/
|
2022-08-08 17:40:12 +08:00
|
|
|
static <T> boolean iterate(T object, ItemStack trigger, IStructureElement<T>[] elements, World world,
|
|
|
|
|
ExtendedFacing extendedFacing, int basePositionX, int basePositionY, int basePositionZ, int basePositionA,
|
|
|
|
|
int basePositionB, int basePositionC, boolean hintsOnly, Boolean checkBlocksIfNotNullForceCheckAllIfTrue) {
|
2022-09-05 20:42:57 +09:00
|
|
|
if (!world.isRemote && hintsOnly) {
|
2022-07-08 17:14:18 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (checkBlocksIfNotNullForceCheckAllIfTrue != null) {
|
2022-08-12 12:25:03 +08:00
|
|
|
boolean success;
|
2022-07-08 17:14:18 +08:00
|
|
|
if (checkBlocksIfNotNullForceCheckAllIfTrue) {
|
2022-08-12 12:25:03 +08:00
|
|
|
success = StructureUtility.iterateV2(
|
|
|
|
|
elements,
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
2022-09-11 02:54:11 +08:00
|
|
|
(e, w, x, y, z, a, b, c) -> e.check(object, w, x, y, z),
|
2022-08-12 12:25:03 +08:00
|
|
|
"check");
|
2022-07-08 17:14:18 +08:00
|
|
|
} else {
|
2022-08-12 12:25:03 +08:00
|
|
|
success = StructureUtility.iterateV2(
|
|
|
|
|
elements,
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
2022-09-11 02:54:11 +08:00
|
|
|
skipBlockUnloaded((e, w, x, y, z, a, b, c) -> e.check(object, w, x, y, z)),
|
2022-08-12 12:25:03 +08:00
|
|
|
"check force");
|
2022-07-08 17:14:18 +08:00
|
|
|
}
|
2022-08-30 23:27:18 +08:00
|
|
|
if (StructureLibAPI.isDebugEnabled() && success) {
|
2022-08-08 17:40:12 +08:00
|
|
|
StructureLib.LOGGER
|
|
|
|
|
.info("Multi [" + basePositionX + ", " + basePositionY + ", " + basePositionZ + "] pass");
|
2022-07-08 17:14:18 +08:00
|
|
|
}
|
2022-08-12 12:25:03 +08:00
|
|
|
return success;
|
2022-07-08 17:14:18 +08:00
|
|
|
} else {
|
|
|
|
|
if (hintsOnly) {
|
2022-08-12 12:25:03 +08:00
|
|
|
StructureUtility.iterateV2(
|
|
|
|
|
elements,
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
2022-09-11 02:54:11 +08:00
|
|
|
ignoreBlockUnloaded((e, w, x, y, z, a, b, c) -> {
|
2022-08-20 19:27:33 +08:00
|
|
|
e.spawnHint(object, world, x, y, z, trigger);
|
2025-04-30 21:55:19 +08:00
|
|
|
if (ChannelDataAccessor.hasSubChannel(trigger, StructureLibAPI.CHANNEL_SHOW_ERROR)
|
2024-12-14 13:13:34 -05:00
|
|
|
&& !e.couldBeValid(object, world, x, y, z, trigger)) {
|
|
|
|
|
StructureLibAPI.markHintParticleError(StructureLib.getCurrentPlayer(), world, x, y, z);
|
|
|
|
|
}
|
2022-08-20 19:27:33 +08:00
|
|
|
return true;
|
|
|
|
|
}),
|
2022-08-12 12:25:03 +08:00
|
|
|
"spawnHint");
|
2022-07-08 17:14:18 +08:00
|
|
|
} else {
|
2022-08-12 12:25:03 +08:00
|
|
|
StructureUtility.iterateV2(
|
|
|
|
|
elements,
|
|
|
|
|
world,
|
|
|
|
|
extendedFacing,
|
|
|
|
|
basePositionX,
|
|
|
|
|
basePositionY,
|
|
|
|
|
basePositionZ,
|
|
|
|
|
basePositionA,
|
|
|
|
|
basePositionB,
|
|
|
|
|
basePositionC,
|
2022-09-11 02:54:11 +08:00
|
|
|
ignoreBlockUnloaded((e, w, x, y, z, a, b, c) -> {
|
2022-08-20 19:27:33 +08:00
|
|
|
e.placeBlock(object, world, x, y, z, trigger);
|
|
|
|
|
return true;
|
|
|
|
|
}),
|
2022-08-12 12:25:03 +08:00
|
|
|
"placeBlock");
|
2022-07-08 17:14:18 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-30 23:27:18 +08:00
|
|
|
/**
|
|
|
|
|
* Create a new instance of builder.
|
2024-12-14 13:13:34 -05:00
|
|
|
*
|
2022-08-30 23:27:18 +08:00
|
|
|
* @param <T> type of context object
|
|
|
|
|
*/
|
2022-07-08 17:14:18 +08:00
|
|
|
static <T> StructureDefinition.Builder<T> builder() {
|
|
|
|
|
return StructureDefinition.builder();
|
|
|
|
|
}
|
2021-05-17 03:02:24 +08:00
|
|
|
}
|