2021-05-17 03:02:24 +08:00
package com.gtnewhorizon.structurelib.structure ;
2021-05-29 19:05:50 +08:00
import com.gtnewhorizon.structurelib.StructureLibAPI ;
2021-05-17 03:02:24 +08:00
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing ;
import com.gtnewhorizon.structurelib.structure.adders.IBlockAdder ;
import com.gtnewhorizon.structurelib.structure.adders.ITileAdder ;
import com.gtnewhorizon.structurelib.util.Vec3Impl ;
2021-07-19 14:47:27 +08:00
import cpw.mods.fml.common.registry.GameRegistry ;
2021-05-17 03:02:24 +08:00
import net.minecraft.block.Block ;
import net.minecraft.init.Blocks ;
import net.minecraft.item.ItemStack ;
import net.minecraft.tileentity.TileEntity ;
import net.minecraft.util.IIcon ;
import net.minecraft.world.World ;
2021-07-19 14:47:27 +08:00
import org.apache.commons.lang3.StringUtils ;
2021-07-22 12:07:12 +08:00
import org.apache.commons.lang3.tuple.Pair ;
2021-05-17 03:02:24 +08:00
2021-07-22 12:07:12 +08:00
import javax.annotation.Nullable ;
2021-07-19 14:47:27 +08:00
import java.util.Collection ;
import java.util.Collections ;
import java.util.Comparator ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.List ;
import java.util.Map ;
2021-07-22 12:07:12 +08:00
import java.util.Objects ;
2021-07-19 14:47:27 +08:00
import java.util.Set ;
import java.util.TreeMap ;
import java.util.TreeSet ;
2021-07-22 12:07:12 +08:00
import java.util.function.BiConsumer ;
2021-07-19 14:47:27 +08:00
import java.util.function.BiFunction ;
import java.util.function.BiPredicate ;
import java.util.function.Consumer ;
import java.util.function.Function ;
2021-07-22 12:07:12 +08:00
import java.util.function.IntBinaryOperator ;
2021-07-19 14:47:27 +08:00
import java.util.function.Supplier ;
2021-05-17 03:02:24 +08:00
import static java.lang.Integer.MIN_VALUE ;
/**
* Fluent API for structure checking!
* <p>
* (Just import static this class to have a nice fluent syntax while defining structure definitions)
*/
public class StructureUtility {
private static final String NICE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz=|!@#$%&()[]{};:<>/?_,.*^'`" ;
@SuppressWarnings ( "rawtypes" )
private static final Map < Vec3Impl , IStructureNavigate > STEP = new HashMap <> ();
@SuppressWarnings ( "rawtypes" )
private static final IStructureElement AIR = new IStructureElement () {
@Override
public boolean check ( Object t , World world , int x , int y , int z ) {
return world . isAirBlock ( x , y , z );
}
@Override
public boolean spawnHint ( Object o , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , StructureLibAPI . getBlockHint (), 13 );
2021-05-17 03:02:24 +08:00
return true ;
}
@Override
public boolean placeBlock ( Object o , World world , int x , int y , int z , ItemStack trigger ) {
world . setBlock ( x , y , z , Blocks . air , 0 , 2 );
return false ;
}
};
@SuppressWarnings ( "rawtypes" )
private static final IStructureElement NOT_AIR = new IStructureElement () {
@Override
public boolean check ( Object t , World world , int x , int y , int z ) {
return ! world . isAirBlock ( x , y , z );
}
@Override
public boolean spawnHint ( Object o , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , StructureLibAPI . getBlockHint (), 14 );
2021-05-17 03:02:24 +08:00
return true ;
}
@Override
public boolean placeBlock ( Object o , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
world . setBlock ( x , y , z , StructureLibAPI . getBlockHint (), 14 , 2 );
2021-05-17 03:02:24 +08:00
return true ;
}
};
@SuppressWarnings ( "rawtypes" )
private static final IStructureElement ERROR = new IStructureElement () {
@Override
public boolean check ( Object t , World world , int x , int y , int z ) {
return false ;
}
@Override
public boolean spawnHint ( Object o , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , StructureLibAPI . getBlockHint (), 15 );
2021-05-17 03:02:24 +08:00
return true ;
}
@Override
public boolean placeBlock ( Object o , World world , int x , int y , int z , ItemStack trigger ) {
return true ;
}
};
private StructureUtility () {
}
@SuppressWarnings ( "unchecked" )
public static < T > IStructureElement < T > isAir () {
return AIR ;
}
@SuppressWarnings ( "unchecked" )
public static < T > IStructureElement < T > notAir () {
return NOT_AIR ;
}
/**
* Check returns false.
* Placement is always handled by this and does nothing.
* Makes little to no use it in fallback chain.
*
*/
@SuppressWarnings ( "unchecked" )
public static < T > IStructureElement < T > error () {
return ERROR ;
}
//region hint only
/**
* Check always returns: true.
*
*/
public static < T > IStructureElementNoPlacement < T > ofHint ( int dots ) {
int meta = dots - 1 ;
return new IStructureElementNoPlacement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , StructureLibAPI . getBlockHint (), meta );
2021-05-17 03:02:24 +08:00
return false ;
}
};
}
/**
* Check always returns: true.
*
*/
public static < T > IStructureElementNoPlacement < T > ofHintDeferred ( Supplier < IIcon []> icons ) {
return new IStructureElementNoPlacement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , icons . get ());
2021-05-17 03:02:24 +08:00
return false ;
}
};
}
/**
* Check always returns: true.
*
*/
public static < T > IStructureElementNoPlacement < T > ofHintDeferred ( Supplier < IIcon []> icons , short [] RGBa ) {
return new IStructureElementNoPlacement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticleTinted ( world , x , y , z , icons . get (), RGBa );
2021-05-17 03:02:24 +08:00
return false ;
}
};
}
//endregion
//region block
2021-07-22 12:07:12 +08:00
/**
* A more primitive variant of {@link #ofBlocksTiered(ITierConverter, List, Object, BiConsumer, Function)}
* Main difference is this one is check only.
* @see #ofBlocksTiered(ITierConverter, Object, BiConsumer, Function)
*/
public static < T , TIER > IStructureElementCheckOnly < T > ofBlocksTiered ( ITierConverter < TIER > tierExtractor , @Nullable TIER notSet , BiConsumer < T , TIER > setter , Function < T , TIER > getter ) {
if ( tierExtractor == null ) throw new IllegalArgumentException ();
if ( setter == null ) throw new IllegalArgumentException ();
if ( getter == null ) throw new IllegalArgumentException ();
return ( t , world , x , y , z ) -> {
Block block = world . getBlock ( x , y , z );
int meta = world . getBlockMetadata ( x , y , z );
TIER tier = tierExtractor . convert ( block , meta );
TIER current = getter . apply ( t );
if ( Objects . equals ( notSet , current )) {
setter . accept ( t , tier );
return true ;
}
return Objects . equals ( current , tier );
};
}
/**
* Element representing a component with different tiers. Player can use more blueprint to get hints denoting more
* advanced components.
*
* There is yet no TileEntity counter part of this utility. Feel free to submit a PR to add it.
* @param allKnownTiers All known tiers as of calling. Can be empty or null. No hint will be spawned if empty or null. Cannot have null elements.
* First element denotes the most primitive tier. Last element denotes the most advanced tier.
* If not all tiers are available at definition construction time, use {@link #lazy(Supplier)} or its overloads to delay a little bit.
* @param notSet The value returned from {@code getter} when there were no tier info found in T yet. Can be null.
* @param getter a function to retrieve the current tier from T
* @param setter a function to set the current tier into T
* @param tierExtractor a function to extract tier info from a block.
*/
public static < T , TIER > IStructureElement < T > ofBlocksTiered ( ITierConverter < TIER > tierExtractor , @Nullable List < Pair < Block , Integer >> allKnownTiers , @Nullable TIER notSet , BiConsumer < T , TIER > setter , Function < T , TIER > getter ) {
List < Pair < Block , Integer >> hints = allKnownTiers == null ? Collections . emptyList () : allKnownTiers ;
if ( hints . stream (). anyMatch ( Objects :: isNull )) throw new IllegalArgumentException ();
IStructureElementCheckOnly < T > check = ofBlocksTiered ( tierExtractor , notSet , setter , getter );
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return check . check ( t , world , x , y , z );
}
private Pair < Block , Integer > getHint ( ItemStack trigger ) {
return hints . get ( Math . min ( Math . max ( trigger . stackSize , 1 ), hints . size ()));
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
Pair < Block , Integer > hint = getHint ( trigger );
if ( hint == null )
return false ;
StructureLibAPI . hintParticle ( world , x , y , z , hint . getKey (), hint . getValue ());
return true ;
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
Pair < Block , Integer > hint = getHint ( trigger );
if ( hint == null )
return false ;
if ( hint . getKey () instanceof ICustomBlockSetting ) {
ICustomBlockSetting block = ( ICustomBlockSetting ) hint . getKey ();
block . setBlock ( world , x , y , z , hint . getValue ());
} else {
world . setBlock ( x , y , z , hint . getKey (), hint . getValue (), 2 );
}
return true ;
}
};
}
2021-07-19 14:47:27 +08:00
/**
* Denote a block using unlocalized names. This can be useful to get around mod loading order issues.
* <p>
* While no immediate error will be thrown, client code should ensure said mod is loaded and
* said mod is present, otherwise bad things will happen later!
*/
public static < T > IStructureElement < T > ofBlockUnlocalizedName ( String modid , String unlocalizedName , int meta ) {
if ( StringUtils . isBlank ( unlocalizedName )) throw new IllegalArgumentException ();
if ( meta < 0 ) throw new IllegalArgumentException ();
if ( meta > 15 ) throw new IllegalArgumentException ();
if ( StringUtils . isBlank ( modid )) throw new IllegalArgumentException ();
return new IStructureElement < T > () {
private Block block ;
private Block getBlock () {
if ( block == null )
block = GameRegistry . findBlock ( modid , unlocalizedName );
return block ;
}
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return world . getBlock ( x , y , z ) != getBlock () && world . getBlockMetadata ( x , y , z ) == meta ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
StructureLibAPI . hintParticle ( world , x , y , z , getBlock (), meta );
return true ;
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
world . setBlock ( x , y , z , getBlock (), meta , 2 );
return true ;
}
};
}
/**
* Similiar to the other overload, but allows client code to specify a fallback in case said block was not found later
* when the element got called.
*
* This is slightly different to using the other overload and another element in a {@link #ofChain(IStructureElement[])},
* as that combination would cause crash, where this won't.
*/
public static < T > IStructureElement < T > ofBlockUnlocalizedName ( String modid , String unlocalizedName , int meta , IStructureElement < T > fallback ) {
if ( StringUtils . isBlank ( unlocalizedName )) throw new IllegalArgumentException ();
if ( meta < 0 ) throw new IllegalArgumentException ();
if ( meta > 15 ) throw new IllegalArgumentException ();
if ( StringUtils . isBlank ( modid )) throw new IllegalArgumentException ();
if ( fallback == null ) throw new IllegalArgumentException ();
return new IStructureElement < T > () {
private Block block ;
private boolean initialized ;
private boolean init () {
if ( ! initialized ) {
block = GameRegistry . findBlock ( modid , unlocalizedName );
initialized = true ;
}
return block != null ;
}
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
if ( init ())
return world . getBlock ( x , y , z ) != block && world . getBlockMetadata ( x , y , z ) == meta ;
else
return fallback . check ( t , world , x , y , z );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
if ( init ()) {
StructureLibAPI . hintParticle ( world , x , y , z , block , meta );
return true ;
} else
return fallback . spawnHint ( t , world , x , y , z , trigger );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
if ( init ()) {
world . setBlock ( x , y , z , block , meta , 2 );
return true ;
} else
return fallback . placeBlock ( t , world , x , y , z , trigger );
}
};
}
2021-05-17 03:02:24 +08:00
/**
* Does not allow Block duplicates (with different meta)
*/
public static < T > IStructureElementNoPlacement < T > ofBlocksFlatHint ( Map < Block , Integer > blocsMap , Block hintBlock , int hintMeta ) {
if ( blocsMap == null || blocsMap . isEmpty () || hintBlock == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementNoPlacement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return blocsMap . getOrDefault ( worldBlock , MIN_VALUE ) == worldBlock . getDamageValue ( world , x , y , z );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , hintBlock , hintMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
}
/**
* Allows block duplicates (with different meta)
*/
public static < T > IStructureElementNoPlacement < T > ofBlocksMapHint ( Map < Block , Collection < Integer >> blocsMap , Block hintBlock , int hintMeta ) {
if ( blocsMap == null || blocsMap . isEmpty () || hintBlock == null ) {
throw new IllegalArgumentException ();
}
for ( Collection < Integer > value : blocsMap . values ()) {
if ( value . isEmpty ()) {
throw new IllegalArgumentException ();
}
}
return new IStructureElementNoPlacement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return blocsMap . getOrDefault ( worldBlock , Collections . emptySet ()). contains ( worldBlock . getDamageValue ( world , x , y , z ));
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , hintBlock , hintMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
}
public static < T > IStructureElementNoPlacement < T > ofBlockHint ( Block block , int meta , Block hintBlock , int hintMeta ) {
if ( block == null || hintBlock == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementNoPlacement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return block == worldBlock && meta == worldBlock . getDamageValue ( world , x , y , z );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , hintBlock , hintMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
}
public static < T > IStructureElementNoPlacement < T > ofBlockHint ( Block block , int meta ) {
return ofBlockHint ( block , meta , block , meta );
}
public static < T > IStructureElementNoPlacement < T > ofBlockAdderHint ( IBlockAdder < T > iBlockAdder , Block hintBlock , int hintMeta ) {
if ( iBlockAdder == null || hintBlock == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementNoPlacement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return iBlockAdder . apply ( t , worldBlock , worldBlock . getDamageValue ( world , x , y , z ));
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , hintBlock , hintMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
}
/**
* Does not allow Block duplicates (with different meta)
*/
public static < T > IStructureElement < T > ofBlocksFlat ( Map < Block , Integer > blocsMap , Block defaultBlock , int defaultMeta ) {
if ( blocsMap == null || blocsMap . isEmpty () || defaultBlock == null ) {
throw new IllegalArgumentException ();
}
if ( defaultBlock instanceof ICustomBlockSetting ) {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return blocsMap . getOrDefault ( worldBlock , MIN_VALUE ) == worldBlock . getDamageValue ( world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
(( ICustomBlockSetting ) defaultBlock ). setBlock ( world , x , y , z , defaultMeta );
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , defaultBlock , defaultMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
} else {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return blocsMap . getOrDefault ( worldBlock , MIN_VALUE ) == worldBlock . getDamageValue ( world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
world . setBlock ( x , y , z , defaultBlock , defaultMeta , 2 );
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , defaultBlock , defaultMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
}
}
/**
* Allows block duplicates (with different meta)
*/
public static < T > IStructureElement < T > ofBlocksMap ( Map < Block , Collection < Integer >> blocsMap , Block defaultBlock , int defaultMeta ) {
if ( blocsMap == null || blocsMap . isEmpty () || defaultBlock == null ) {
throw new IllegalArgumentException ();
}
for ( Collection < Integer > value : blocsMap . values ()) {
if ( value . isEmpty ()) {
throw new IllegalArgumentException ();
}
}
if ( defaultBlock instanceof ICustomBlockSetting ) {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return blocsMap . getOrDefault ( worldBlock , Collections . emptySet ()). contains ( worldBlock . getDamageValue ( world , x , y , z ));
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
(( ICustomBlockSetting ) defaultBlock ). setBlock ( world , x , y , z , defaultMeta );
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , defaultBlock , defaultMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
} else {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return blocsMap . getOrDefault ( worldBlock , Collections . emptySet ()). contains ( worldBlock . getDamageValue ( world , x , y , z ));
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
world . setBlock ( x , y , z , defaultBlock , defaultMeta , 2 );
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , defaultBlock , defaultMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
}
}
public static < T > IStructureElement < T > ofBlock ( Block block , int meta , Block defaultBlock , int defaultMeta ) {
if ( block == null || defaultBlock == null ) {
throw new IllegalArgumentException ();
}
if ( block instanceof ICustomBlockSetting ) {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return block == worldBlock && meta == worldBlock . getDamageValue ( world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
(( ICustomBlockSetting ) defaultBlock ). setBlock ( world , x , y , z , defaultMeta );
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , defaultBlock , defaultMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
} else {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return block == worldBlock && meta == worldBlock . getDamageValue ( world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
world . setBlock ( x , y , z , defaultBlock , defaultMeta , 2 );
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , defaultBlock , defaultMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
}
}
/**
* Same as above but ignores target meta id
*/
public static < T > IStructureElement < T > ofBlockAnyMeta ( Block block , Block defaultBlock , int defaultMeta ) {
if ( block == null || defaultBlock == null ) {
throw new IllegalArgumentException ();
}
if ( block instanceof ICustomBlockSetting ) {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return block == world . getBlock ( x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
(( ICustomBlockSetting ) defaultBlock ). setBlock ( world , x , y , z , defaultMeta );
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , defaultBlock , defaultMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
} else {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return block == world . getBlock ( x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
world . setBlock ( x , y , z , defaultBlock , defaultMeta , 2 );
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , defaultBlock , defaultMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
}
}
public static < T > IStructureElement < T > ofBlock ( Block block , int meta ) {
return ofBlock ( block , meta , block , meta );
}
/**
* Same as above but ignores target meta id
*/
public static < T > IStructureElement < T > ofBlockAnyMeta ( Block block ) {
return ofBlockAnyMeta ( block , block , 0 );
}
/**
* Same as above but allows to set hint particle render
*/
public static < T > IStructureElement < T > ofBlockAnyMeta ( Block block , int defaultMeta ) {
return ofBlockAnyMeta ( block , block , defaultMeta );
}
//endregion
//region adders
public static < T > IStructureElement < T > ofBlockAdder ( IBlockAdder < T > iBlockAdder , Block defaultBlock , int defaultMeta ) {
if ( iBlockAdder == null || defaultBlock == null ) {
throw new IllegalArgumentException ();
}
if ( defaultBlock instanceof ICustomBlockSetting ) {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return iBlockAdder . apply ( t , worldBlock , worldBlock . getDamageValue ( world , x , y , z ));
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
(( ICustomBlockSetting ) defaultBlock ). setBlock ( world , x , y , z , defaultMeta );
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , defaultBlock , defaultMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
} else {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
Block worldBlock = world . getBlock ( x , y , z );
return iBlockAdder . apply ( t , worldBlock , worldBlock . getDamageValue ( world , x , y , z ));
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
world . setBlock ( x , y , z , defaultBlock , defaultMeta , 2 );
return true ;
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , defaultBlock , defaultMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
}
}
public static < T > IStructureElement < T > ofBlockAdder ( IBlockAdder < T > iBlockAdder , int dots ) {
2021-05-29 19:05:50 +08:00
return ofBlockAdder ( iBlockAdder , StructureLibAPI . getBlockHint (), dots - 1 );
2021-05-17 03:02:24 +08:00
}
public static < T > IStructureElementNoPlacement < T > ofTileAdder ( ITileAdder < T > iTileAdder , Block hintBlock , int hintMeta ) {
if ( iTileAdder == null || hintBlock == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementNoPlacement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
TileEntity tileEntity = world . getTileEntity ( x , y , z );
// This used to check if it's a GT tile. Since this is now an standalone mod we no longer do this
return iTileAdder . apply ( t , tileEntity );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
2021-05-29 19:05:50 +08:00
StructureLibAPI . hintParticle ( world , x , y , z , hintBlock , hintMeta );
2021-05-17 03:02:24 +08:00
return true ;
}
};
}
2021-06-22 23:58:19 +08:00
public static < T , E > IStructureElementNoPlacement < T > ofSpecificTileAdder ( BiPredicate < T , E > iTileAdder , Class < E > tileClass , Block hintBlock , int hintMeta ) {
if ( iTileAdder == null || hintBlock == null || tileClass == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementNoPlacement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
TileEntity tileEntity = world . getTileEntity ( x , y , z );
// This used to check if it's a GT tile. Since this is now an standalone mod we no longer do this
return tileClass . isInstance ( tileEntity ) && iTileAdder . test ( t , tileClass . cast ( tileEntity ));
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
StructureLibAPI . hintParticle ( world , x , y , z , hintBlock , hintMeta );
return true ;
}
};
}
2021-05-17 03:02:24 +08:00
// No more hatch adder. Implement it via tile adder. We could of course add a wrapper around it in gregtech, but not any more in this standalone mod.
//endregion
//region side effects
public static < B extends IStructureElement < T > , T > IStructureElement < T > onElementPass ( Consumer < T > onCheckPass , B element ) {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
boolean check = element . check ( t , world , x , y , z );
if ( check ) {
onCheckPass . accept ( t );
}
return check ;
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return element . placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return element . spawnHint ( t , world , x , y , z , trigger );
}
};
}
public static < B extends IStructureElement < T > , T > IStructureElement < T > onElementFail ( Consumer < T > onFail , B element ) {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
boolean check = element . check ( t , world , x , y , z );
if ( ! check ) {
onFail . accept ( t );
}
return check ;
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return element . placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return element . spawnHint ( t , world , x , y , z , trigger );
}
};
}
//endregion
/**
* Take care while chaining, as it will try to call every structure element until it returns true.
* If none does it will finally return false.
*
*/
@SafeVarargs
public static < T > IStructureElementChain < T > ofChain ( IStructureElement < T > ... elementChain ) {
if ( elementChain == null || elementChain . length == 0 ) {
throw new IllegalArgumentException ();
}
for ( IStructureElement < T > iStructureElement : elementChain ) {
if ( iStructureElement == null ) {
throw new IllegalArgumentException ();
}
}
return () -> elementChain ;
}
/**
* Take care while chaining, as it will try to call every structure element until it returns true.
* If none does it will finally return false.
*
*/
@SuppressWarnings ( "unchecked" )
public static < T > IStructureElementChain < T > ofChain ( List < IStructureElement < T >> elementChain ) {
return ofChain ( elementChain . toArray ( new IStructureElement [ 0 ] ));
}
2021-06-22 23:58:19 +08:00
// region context
public static < CTX , T extends IWithExtendedContext < CTX > , E extends IStructureElement < CTX >> IStructureElement < T > withContext ( E elem ) {
return new IStructureElement < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return elem . check ( t . getCurrentContext (), world , x , y , z );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return elem . spawnHint ( t . getCurrentContext (), world , x , y , z , trigger );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return elem . placeBlock ( t . getCurrentContext (), world , x , y , z , trigger );
}
};
}
//endregion
2021-05-17 03:02:24 +08:00
//region defer
2021-07-19 17:45:18 +08:00
/**
* Similar to defer, but caches the first returned element returned and won't call it again.
* Initialization is not thread safe.
*/
public static < T > IStructureElementDeferred < T > lazy ( Supplier < IStructureElement < T >> to ) {
if ( to == null ) {
throw new IllegalArgumentException ();
}
return new LazyStructureElement <> ( t -> to . get ());
}
/**
* Similar to defer, but caches the first returned element returned and won't call it again.
* Initialization is not thread safe.
*/
public static < T > IStructureElementDeferred < T > lazy ( Function < T , IStructureElement < T >> to ) {
if ( to == null ) {
throw new IllegalArgumentException ();
}
return new LazyStructureElement <> ( to );
}
2021-05-17 03:02:24 +08:00
public static < T > IStructureElementDeferred < T > defer ( Supplier < IStructureElement < T >> to ) {
if ( to == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return to . get (). check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return to . get (). placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return to . get (). spawnHint ( t , world , x , y , z , trigger );
}
};
}
public static < T > IStructureElementDeferred < T > defer ( Function < T , IStructureElement < T >> to ) {
if ( to == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return to . apply ( t ). check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return to . apply ( t ). placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return to . apply ( t ). spawnHint ( t , world , x , y , z , trigger );
}
};
}
public static < T , K > IStructureElementDeferred < T > defer ( Function < T , K > keyExtractor , Map < K , IStructureElement < T >> map ) {
if ( keyExtractor == null || map == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return map . get ( keyExtractor . apply ( t )). check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . get ( keyExtractor . apply ( t )). placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . get ( keyExtractor . apply ( t )). spawnHint ( t , world , x , y , z , trigger );
}
};
}
public static < T , K > IStructureElementDeferred < T > defer ( Function < T , K > keyExtractor , Map < K , IStructureElement < T >> map , IStructureElement < T > defaultElem ) {
if ( keyExtractor == null || map == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return map . getOrDefault ( keyExtractor . apply ( t ), defaultElem ). check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . getOrDefault ( keyExtractor . apply ( t ), defaultElem ). placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . getOrDefault ( keyExtractor . apply ( t ), defaultElem ). spawnHint ( t , world , x , y , z , trigger );
}
};
}
@SafeVarargs
public static < T > IStructureElementDeferred < T > defer ( Function < T , Integer > keyExtractor , IStructureElement < T > ... array ) {
if ( keyExtractor == null || array == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return array [ keyExtractor . apply ( t ) ] . check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return array [ keyExtractor . apply ( t ) ] . placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return array [ keyExtractor . apply ( t ) ] . spawnHint ( t , world , x , y , z , trigger );
}
};
}
@SuppressWarnings ( "unchecked" )
public static < T > IStructureElementDeferred < T > defer ( Function < T , Integer > keyExtractor , List < IStructureElement < T >> array ) {
return defer ( keyExtractor , array . toArray ( new IStructureElement [ 0 ] ));
}
public static < T > IStructureElementDeferred < T > defer ( BiFunction < T , ItemStack , IStructureElement < T >> to ) {
if ( to == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return to . apply ( t , null ). check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return to . apply ( t , trigger ). placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return to . apply ( t , trigger ). spawnHint ( t , world , x , y , z , trigger );
}
};
}
public static < T , K > IStructureElementDeferred < T > defer ( BiFunction < T , ItemStack , K > keyExtractor , Map < K , IStructureElement < T >> map ) {
if ( keyExtractor == null || map == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return map . get ( keyExtractor . apply ( t , null )). check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . get ( keyExtractor . apply ( t , trigger )). placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . get ( keyExtractor . apply ( t , trigger )). spawnHint ( t , world , x , y , z , trigger );
}
};
}
public static < T , K > IStructureElementDeferred < T > defer ( BiFunction < T , ItemStack , K > keyExtractor , Map < K , IStructureElement < T >> map , IStructureElement < T > defaultElem ) {
if ( keyExtractor == null || map == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return map . getOrDefault ( keyExtractor . apply ( t , null ), defaultElem ). check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . getOrDefault ( keyExtractor . apply ( t , trigger ), defaultElem ). placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . getOrDefault ( keyExtractor . apply ( t , trigger ), defaultElem ). spawnHint ( t , world , x , y , z , trigger );
}
};
}
@SafeVarargs
public static < T > IStructureElementDeferred < T > defer ( BiFunction < T , ItemStack , Integer > keyExtractor , IStructureElement < T > ... array ) {
if ( keyExtractor == null || array == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return array [ keyExtractor . apply ( t , null ) ] . check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return array [ keyExtractor . apply ( t , trigger ) ] . placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return array [ keyExtractor . apply ( t , trigger ) ] . spawnHint ( t , world , x , y , z , trigger );
}
};
}
@SuppressWarnings ( "unchecked" )
public static < T > IStructureElementDeferred < T > defer ( BiFunction < T , ItemStack , Integer > keyExtractor , List < IStructureElement < T >> array ) {
return defer ( keyExtractor , array . toArray ( new IStructureElement [ 0 ] ));
}
public static < T > IStructureElementDeferred < T > defer ( Function < T , IStructureElement < T >> toCheck , BiFunction < T , ItemStack , IStructureElement < T >> to ) {
if ( to == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return toCheck . apply ( t ). check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return to . apply ( t , trigger ). placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return to . apply ( t , trigger ). spawnHint ( t , world , x , y , z , trigger );
}
};
}
public static < T , K > IStructureElementDeferred < T > defer ( Function < T , K > keyExtractorCheck , BiFunction < T , ItemStack , K > keyExtractor , Map < K , IStructureElement < T >> map ) {
if ( keyExtractor == null || map == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return map . get ( keyExtractorCheck . apply ( t )). check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . get ( keyExtractor . apply ( t , trigger )). placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . get ( keyExtractor . apply ( t , trigger )). spawnHint ( t , world , x , y , z , trigger );
}
};
}
public static < T , K > IStructureElementDeferred < T > defer ( Function < T , K > keyExtractorCheck , BiFunction < T , ItemStack , K > keyExtractor , Map < K , IStructureElement < T >> map , IStructureElement < T > defaultElem ) {
if ( keyExtractor == null || map == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return map . getOrDefault ( keyExtractorCheck . apply ( t ), defaultElem ). check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . getOrDefault ( keyExtractor . apply ( t , trigger ), defaultElem ). placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return map . getOrDefault ( keyExtractor . apply ( t , trigger ), defaultElem ). spawnHint ( t , world , x , y , z , trigger );
}
};
}
@SafeVarargs
public static < T > IStructureElementDeferred < T > defer ( Function < T , Integer > keyExtractorCheck , BiFunction < T , ItemStack , Integer > keyExtractor , IStructureElement < T > ... array ) {
if ( keyExtractor == null || array == null ) {
throw new IllegalArgumentException ();
}
return new IStructureElementDeferred < T > () {
@Override
public boolean check ( T t , World world , int x , int y , int z ) {
return array [ keyExtractorCheck . apply ( t ) ] . check ( t , world , x , y , z );
}
@Override
public boolean placeBlock ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return array [ keyExtractor . apply ( t , trigger ) ] . placeBlock ( t , world , x , y , z , trigger );
}
@Override
public boolean spawnHint ( T t , World world , int x , int y , int z , ItemStack trigger ) {
return array [ keyExtractor . apply ( t , trigger ) ] . spawnHint ( t , world , x , y , z , trigger );
}
};
}
@SuppressWarnings ( "unchecked" )
public static < T > IStructureElementDeferred < T > defer ( Function < T , Integer > keyExtractorCheck , BiFunction < T , ItemStack , Integer > keyExtractor , List < IStructureElement < T >> array ) {
return defer ( keyExtractorCheck , keyExtractor , array . toArray ( new IStructureElement [ 0 ] ));
}
//endregion
/**
* Used internally, to generate skips for structure definitions
*
*/
public static < T > IStructureNavigate < T > step ( int a , int b , int c ) {
return step ( new Vec3Impl ( a , b , c ));
}
/**
* Used internally, to generate skips for structure definitions
*
*/
@SuppressWarnings ( "unchecked" )
public static < T > IStructureNavigate < T > step ( Vec3Impl step ) {
if ( step == null || step . get0 () < 0 || step . get1 () < 0 || step . get2 () < 0 ) {
throw new IllegalArgumentException ();
}
return STEP . computeIfAbsent ( step , vec3 -> {
if ( vec3 . get2 () > 0 ) {
return stepC ( vec3 . get0 (), vec3 . get1 (), vec3 . get2 ());
} else if ( vec3 . get1 () > 0 ) {
return stepB ( vec3 . get0 (), vec3 . get1 (), vec3 . get2 ());
} else {
return stepA ( vec3 . get0 (), vec3 . get1 (), vec3 . get2 ());
}
});
}
private static < T > IStructureNavigate < T > stepA ( int a , int b , int c ) {
return new IStructureNavigate < T > () {
@Override
public int getStepA () {
return a ;
}
@Override
public int getStepB () {
return b ;
}
@Override
public int getStepC () {
return c ;
}
};
}
private static < T > IStructureNavigate < T > stepB ( int a , int b , int c ) {
return new IStructureNavigate < T > () {
@Override
public int getStepA () {
return a ;
}
@Override
public int getStepB () {
return b ;
}
@Override
public int getStepC () {
return c ;
}
@Override
public boolean resetA () {
return true ;
}
};
}
private static < T > IStructureNavigate < T > stepC ( int a , int b , int c ) {
return new IStructureNavigate < T > () {
@Override
public int getStepA () {
return a ;
}
@Override
public int getStepB () {
return b ;
}
@Override
public int getStepC () {
return c ;
}
@Override
public boolean resetA () {
return true ;
}
@Override
public boolean resetB () {
return true ;
}
};
}
/**
* Used only to get pseudo code in structure writer...
*
* NOTE: GT specific code got removed. TODO add a mean
* @param tileEntityClassifier return a string that denote the type of a tile entity, or null if it's nothing special. useful if the tile entity cannot be simply distinguished via getClass.
*/
public static String getPseudoJavaCode ( World world , ExtendedFacing extendedFacing ,
int basePositionX , int basePositionY , int basePositionZ ,
int basePositionA , int basePositionB , int basePositionC ,
Function <? super TileEntity , String > tileEntityClassifier ,
int sizeA , int sizeB , int sizeC , boolean transpose ) {
Map < Block , Set < Integer >> blocks = new TreeMap <> ( Comparator . comparing ( Block :: getUnlocalizedName ));
Set < Class <? extends TileEntity >> tiles = new HashSet <> ();
Set < String > specialTiles = new HashSet <> ();
iterate ( world , extendedFacing , basePositionX , basePositionY , basePositionZ ,
basePositionA , basePositionB , basePositionC ,
sizeA , sizeB , sizeC , (( w , x , y , z ) -> {
TileEntity tileEntity = w . getTileEntity ( x , y , z );
if ( tileEntity == null ) {
Block block = w . getBlock ( x , y , z );
if ( block != null && block != Blocks . air ) {
blocks . compute ( block , ( b , set ) -> {
if ( set == null ) {
set = new TreeSet <> ();
}
set . add ( block . getDamageValue ( world , x , y , z ));
return set ;
});
}
} else {
String classification = tileEntityClassifier . apply ( tileEntity );
if ( classification == null ) {
tiles . add ( tileEntity . getClass ());
} else
specialTiles . add ( classification );
}
}));
Map < String , Character > map = new HashMap <> ();
StringBuilder builder = new StringBuilder ();
{
int i = 0 ;
char c ;
builder . append ( "\n\nStructure:\n" )
. append ( "\nBlocks:\n" );
for ( Map . Entry < Block , Set < Integer >> entry : blocks . entrySet ()) {
Block block = entry . getKey ();
Set < Integer > set = entry . getValue ();
for ( Integer meta : set ) {
c = NICE_CHARS . charAt ( i ++ );
if ( i > NICE_CHARS . length ()) {
return "Too complicated for nice chars" ;
}
map . put ( block . getUnlocalizedName () + '\0' + meta , c );
builder . append ( c ). append ( " -> ofBlock...(" )
. append ( block . getUnlocalizedName ()). append ( ", " ). append ( meta ). append ( ", ...);\n" );
}
}
builder . append ( "\nTiles:\n" );
for ( Class <? extends TileEntity > tile : tiles ) {
c = NICE_CHARS . charAt ( i ++ );
if ( i > NICE_CHARS . length ()) {
return "Too complicated for nice chars" ;
}
map . put ( tile . getCanonicalName (), c );
builder . append ( c ). append ( " -> ofTileAdder(" )
. append ( tile ). append ( ", ...);\n" );
}
builder . append ( "\nSpecial Tiles:\n" );
for ( String tile : specialTiles ) {
c = NICE_CHARS . charAt ( i ++ );
if ( i > NICE_CHARS . length ()) {
return "Too complicated for nice chars" ;
}
map . put ( tile , c );
builder . append ( c ). append ( " -> ofSpecialTileAdder(" )
. append ( tile ). append ( ", ...); // You will probably want to change it to something else\n" );
}
}
builder . append ( "\nOffsets:\n" )
. append ( basePositionA ). append ( ' ' ). append ( basePositionB ). append ( ' ' ). append ( basePositionC ). append ( '\n' );
if ( transpose ) {
builder . append ( "\nTransposed Scan:\n" )
. append ( "new String[][]{\n" )
. append ( " {\"" );
iterate ( world , extendedFacing , basePositionX , basePositionY , basePositionZ ,
basePositionA , basePositionB , basePositionC , true ,
sizeA , sizeB , sizeC , (( w , x , y , z ) -> {
TileEntity tileEntity = w . getTileEntity ( x , y , z );
if ( tileEntity == null ) {
Block block = w . getBlock ( x , y , z );
if ( block != null && block != Blocks . air ) {
builder . append ( map . get ( block . getUnlocalizedName () + '\0' + block . getDamageValue ( world , x , y , z )));
} else {
builder . append ( ' ' );
}
} else {
String classification = tileEntityClassifier . apply ( tileEntity );
if ( classification == null ) {
classification = tileEntity . getClass (). getCanonicalName ();
}
builder . append ( map . get ( classification ));
}
}),
() -> builder . append ( "\",\"" ),
() -> {
builder . setLength ( builder . length () - 2 );
builder . append ( "},\n {\"" );
});
builder . setLength ( builder . length () - 8 );
builder . append ( "\n}\n\n" );
} else {
builder . append ( "\nNormal Scan:\n" )
. append ( "new String[][]{{\n" )
. append ( " \"" );
iterate ( world , extendedFacing , basePositionX , basePositionY , basePositionZ ,
basePositionA , basePositionB , basePositionC , false ,
sizeA , sizeB , sizeC , (( w , x , y , z ) -> {
TileEntity tileEntity = w . getTileEntity ( x , y , z );
if ( tileEntity == null ) {
Block block = w . getBlock ( x , y , z );
if ( block != null && block != Blocks . air ) {
builder . append ( map . get ( block . getUnlocalizedName () + '\0' + block . getDamageValue ( world , x , y , z )));
} else {
builder . append ( ' ' );
}
} else {
String classification = tileEntityClassifier . apply ( tileEntity );
if ( classification == null ) {
classification = tileEntity . getClass (). getCanonicalName ();
}
builder . append ( map . get ( classification ));
}
}),
() -> builder . append ( "\",\n" ). append ( " \"" ),
() -> {
builder . setLength ( builder . length () - 7 );
builder . append ( "\n" ). append ( "},{\n" ). append ( " \"" );
});
builder . setLength ( builder . length () - 8 );
builder . append ( "}\n\n" );
}
return ( builder . toString (). replaceAll ( "\"\"" , "E" ));
}
public static void iterate ( World world , ExtendedFacing extendedFacing ,
int basePositionX , int basePositionY , int basePositionZ ,
int basePositionA , int basePositionB , int basePositionC ,
int sizeA , int sizeB , int sizeC ,
IBlockPosConsumer iBlockPosConsumer ) {
sizeA -= basePositionA ;
sizeB -= basePositionB ;
sizeC -= basePositionC ;
int [] abc = new int [ 3 ] ;
int [] xyz = new int [ 3 ] ;
for ( abc [ 2 ] = - basePositionC ; abc [ 2 ] < sizeC ; abc [ 2 ]++ ) {
for ( abc [ 1 ] = - basePositionB ; abc [ 1 ] < sizeB ; abc [ 1 ]++ ) {
for ( abc [ 0 ] = - basePositionA ; abc [ 0 ] < sizeA ; abc [ 0 ]++ ) {
extendedFacing . getWorldOffset ( abc , xyz );
iBlockPosConsumer . consume ( world , xyz [ 0 ] + basePositionX , xyz [ 1 ] + basePositionY , xyz [ 2 ] + basePositionZ );
}
}
}
}
public static void iterate ( World world , ExtendedFacing extendedFacing ,
int basePositionX , int basePositionY , int basePositionZ ,
int basePositionA , int basePositionB , int basePositionC ,
boolean transpose , int sizeA , int sizeB , int sizeC ,
IBlockPosConsumer iBlockPosConsumer ,
Runnable nextB ,
Runnable nextC ) {
sizeA -= basePositionA ;
sizeB -= basePositionB ;
sizeC -= basePositionC ;
int [] abc = new int [ 3 ] ;
int [] xyz = new int [ 3 ] ;
if ( transpose ) {
for ( abc [ 1 ] = - basePositionB ; abc [ 1 ] < sizeB ; abc [ 1 ]++ ) {
for ( abc [ 2 ] = - basePositionC ; abc [ 2 ] < sizeC ; abc [ 2 ]++ ) {
for ( abc [ 0 ] = - basePositionA ; abc [ 0 ] < sizeA ; abc [ 0 ]++ ) {
extendedFacing . getWorldOffset ( abc , xyz );
iBlockPosConsumer . consume ( world , xyz [ 0 ] + basePositionX , xyz [ 1 ] + basePositionY , xyz [ 2 ] + basePositionZ );
}
nextB . run ();
}
nextC . run ();
}
} else {
for ( abc [ 2 ] = - basePositionC ; abc [ 2 ] < sizeC ; abc [ 2 ]++ ) {
for ( abc [ 1 ] = - basePositionB ; abc [ 1 ] < sizeB ; abc [ 1 ]++ ) {
for ( abc [ 0 ] = - basePositionA ; abc [ 0 ] < sizeA ; abc [ 0 ]++ ) {
extendedFacing . getWorldOffset ( abc , xyz );
iBlockPosConsumer . consume ( world , xyz [ 0 ] + basePositionX , xyz [ 1 ] + basePositionY , xyz [ 2 ] + basePositionZ );
}
nextB . run ();
}
nextC . run ();
}
}
}
/**
* Transposes shape (swaps B and C axis, can be used to un-transpose transposed shape)
* WARNING! Do not use on old api...
*
* @param structurePiece shape (transposed shape)
* @return transposed shape (untransposed shape)
*/
public static String [][] transpose ( String [][] structurePiece ) {
String [][] shape = new String [ structurePiece [ 0 ] . length ][ structurePiece . length ] ;
for ( int i = 0 ; i < structurePiece . length ; i ++ ) {
for ( int j = 0 ; j < structurePiece [ i ] . length ; j ++ ) {
shape [ j ][ i ] = structurePiece [ i ][ j ] ;
}
}
return shape ;
}
2021-07-19 17:45:18 +08:00
2021-05-17 03:02:24 +08:00
}