autoplace first commit

This commit is contained in:
Glease committed 2022-07-09 02:39:28 +08:00
1 parent 4c03406640
commit 7c3491d543
29 files changed
+1104 -35

No files matched your search

@@ -9,6 +9,7 @@ import com.gtnewhorizon.structurelib.proxy.CommonProxy;
import com.gtnewhorizon.structurelib.util.XSTR;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
@@ -29,6 +30,7 @@ import org.apache.logging.log4j.Logger;
@Mod(modid = StructureLibAPI.MOD_ID, name = "StructureLib", version = "GRADLETOKEN_VERSION", acceptableRemoteVersions = "*", guiFactory = "com.gtnewhorizon.structurelib.GuiFactory")
public class StructureLib {
public static boolean DEBUG_MODE = Boolean.getBoolean("structurelib.debug");
public static boolean PANIC_MODE = Boolean.getBoolean("structurelib.panic");
public static Logger LOGGER = LogManager.getLogger("StructureLib");
@SidedProxy(serverSide = "com.gtnewhorizon.structurelib.proxy.CommonProxy", clientSide = "com.gtnewhorizon.structurelib.proxy.ClientProxy")
@@ -64,6 +66,11 @@ public class StructureLib {
proxy.preInit(e);
}
@Mod.EventHandler
public void init(FMLInitializationEvent e) {
// TODO register stackExtractors and inventoryExtractors for other mods
}
public static void addClientSideChatMessages(String... messages) {
proxy.addClientSideChatMessages(messages);
}
@@ -75,4 +82,8 @@ public class StructureLib {
public static boolean isCurrentPlayer(EntityPlayer player) {
return proxy.isCurrentPlayer(player);
}
public static long getOverworldTime() {
return proxy.getOverworldTime();
}
}
@@ -3,6 +3,7 @@ package com.gtnewhorizon.structurelib;
import com.gtnewhorizon.structurelib.net.AlignmentMessage;
import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider;
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
import com.gtnewhorizon.structurelib.structure.IItemSource;
import cpw.mods.fml.common.network.NetworkRegistry;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
@@ -12,6 +13,8 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
import java.util.UUID;
import static com.gtnewhorizon.structurelib.StructureLib.proxy;
/**
@@ -70,6 +73,14 @@ public class StructureLibAPI {
proxy.hintParticle(w, x, y, z, block, meta);
}
/**
* Update the tint of given hint particle. Do nothing if particle not found.
* @return false if nothing updated. true if updated or on server side.
*/
public static boolean updateHintParticleTint(World w, int x, int y, int z, short[] RGBa) {
return proxy.updateHintParticleTint(w, x, y, z, RGBa);
}
/**
* Query the ExtendedFacing of this tile entity.
* The ExtendedFacing will later be set onto given tile entity via {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)}
@@ -133,4 +144,15 @@ public class StructureLibAPI {
public static void setDebugEnabled(boolean enabled) {
StructureLib.DEBUG_MODE = enabled;
}
/**
* Determines if given block can be replaced without much effort. The exact predicate clauses is not stable and
* will be changed, but the general idea will always stay the same.
*
* Use this in your {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, IItemSource, UUID)}
*/
public static boolean isBlockTriviallyReplaceable(World w, int x, int y, int z, UUID actorProfile) {
// TODO extend this function a bit
return w.getBlock(x, y, z).isReplaceable(w, x, y, z);
}
}
@@ -4,15 +4,25 @@ import com.gtnewhorizon.structurelib.StructureLib;
import com.gtnewhorizon.structurelib.StructureLibAPI;
import com.gtnewhorizon.structurelib.alignment.IAlignment;
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
import com.gtnewhorizon.structurelib.structure.IItemSource;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.ForgeDirection;
import java.util.UUID;
public class ConstructableUtility {
// TODO make these configurable and expose this to external world
private static final int COOLDOWN = 5;
private static final int BUDGET = 25;
private ConstructableUtility() {
}
@@ -30,25 +40,35 @@ public class ConstructableUtility {
return aPlayer instanceof EntityPlayerMP;
}
if (aPlayer instanceof EntityPlayerMP) {
//struct gen
if (aPlayer.isSneaking() && aPlayer.capabilities.isCreativeMode) {
if (tTileEntity instanceof IConstructableProvider) {
IConstructable constructable = ((IConstructableProvider) tTileEntity).getConstructable();
if (constructable != null) {
constructable.construct(aStack, false);
}
} else if (tTileEntity instanceof IConstructable) {
((IConstructable) tTileEntity).construct(aStack, false);
} else if (IMultiblockInfoContainer.contains(tTileEntity.getClass())) {
IMultiblockInfoContainer<TileEntity> iMultiblockInfoContainer = IMultiblockInfoContainer.get(tTileEntity.getClass());
if (tTileEntity instanceof IAlignment) {
iMultiblockInfoContainer.construct(aStack, false, tTileEntity,
((IAlignment) tTileEntity).getExtendedFacing());
} else {
iMultiblockInfoContainer.construct(aStack, false, tTileEntity,
ExtendedFacing.of(ForgeDirection.getOrientation(aSide)));
}
}
// server side
// not sneaking - client side will generate hologram. nothing to do on server side
if (!aPlayer.isSneaking()) return true;
long timePast = StructureLib.getOverworldTime() - getLastUseTick(aStack);
if (timePast < COOLDOWN) {
aPlayer.addChatComponentMessage(new ChatComponentTranslation("item.structurelib.constructableTrigger.too_fast", COOLDOWN - timePast));
return true;
}
IConstructable constructable = null;
if (tTileEntity instanceof IConstructableProvider)
constructable = ((IConstructableProvider) tTileEntity).getConstructable();
else if (tTileEntity instanceof IConstructable) {
constructable = (IConstructable) tTileEntity;
} else if (IMultiblockInfoContainer.contains(tTileEntity.getClass())) {
ExtendedFacing facing = tTileEntity instanceof IAlignment ?
((IAlignment) tTileEntity).getExtendedFacing() :
ExtendedFacing.of(ForgeDirection.getOrientation(aSide));
constructable = IMultiblockInfoContainer.<TileEntity>get(tTileEntity.getClass()).toConstructable(tTileEntity, facing);
}
if (constructable == null) return false;
if (aPlayer.capabilities.isCreativeMode) {
constructable.construct(aStack, false);
} else if (constructable instanceof ISurvivalConstructable) {
((ISurvivalConstructable) constructable).survivalConstruct(aStack, BUDGET, IItemSource.fromPlayer((EntityPlayerMP) aPlayer), aPlayer.getGameProfile().getId());
setLastUseTickToStackTag(aStack);
}
return true;
} else if (StructureLib.isCurrentPlayer(aPlayer)) {//particles and text client side
@@ -79,4 +99,16 @@ public class ConstructableUtility {
}
return false;
}
private static long getLastUseTick(ItemStack aStack) {
return aStack.hasTagCompound() ? aStack.getTagCompound().getLong("LastUse") : 0;
}
private static void setLastUseTickToStackTag(ItemStack aStack) {
NBTTagCompound tag = aStack.stackTagCompound;
if (tag == null)
tag = aStack.stackTagCompound = new NBTTagCompound();
// here we force use the overworld tick time, in case the current world is over
tag.setLong("LastUse", StructureLib.getOverworldTime());
}
}
@@ -1,12 +1,15 @@
package com.gtnewhorizon.structurelib.alignment.constructable;
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
import com.gtnewhorizon.structurelib.structure.IItemSource;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import java.util.HashMap;
import java.util.UUID;
/**
* To implement IConstructable on not own TileEntities
@@ -33,6 +36,52 @@ public interface IMultiblockInfoContainer<T> {
void construct(ItemStack stackSize, boolean hintsOnly, T tileEntity, ExtendedFacing aSide);
/**
* Construct the structure using {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, IItemSource, UUID)}
* @return -1 if done, a helping pointer
*/
default int survivalConstruct(ItemStack stackSize, int elementBudge, IItemSource source, UUID actorProfile, T tileEntity, ExtendedFacing aSide) {
return -1;
}
@SideOnly(Side.CLIENT)
String[] getDescription(ItemStack stackSize);
/**
* Override this and return {@link #toConstructable(IMultiblockInfoContainer, Object, ExtendedFacing)} if
* {@link #survivalConstruct(ItemStack, int, IItemSource, UUID, Object, ExtendedFacing)} isn't a stub
*/
default IConstructable toConstructable(T tileEntity, ExtendedFacing aSide) {
return new IConstructable() {
@Override
public void construct(ItemStack stackSize, boolean hintsOnly) {
IMultiblockInfoContainer.this.construct(stackSize, hintsOnly, tileEntity, aSide);
}
@Override
public String[] getStructureDescription(ItemStack stackSize) {
return IMultiblockInfoContainer.this.getDescription(stackSize);
}
};
}
static <T> ISurvivalConstructable toConstructable(IMultiblockInfoContainer<T> thiz, T tileEntity, ExtendedFacing aSide) {
return new ISurvivalConstructable() {
@Override
public int survivalConstruct(ItemStack stackSize, int elementBudget, IItemSource source, UUID actorProfile) {
return thiz.survivalConstruct(stackSize, elementBudget, source, actorProfile, tileEntity, aSide);
}
@Override
public void construct(ItemStack stackSize, boolean hintsOnly) {
thiz.construct(stackSize, hintsOnly, tileEntity, aSide);
}
@Override
public String[] getStructureDescription(ItemStack stackSize) {
return thiz.getDescription(stackSize);
}
};
}
}
@@ -0,0 +1,16 @@
package com.gtnewhorizon.structurelib.alignment.constructable;
import com.gtnewhorizon.structurelib.structure.IItemSource;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import java.util.UUID;
public interface ISurvivalConstructable extends IConstructable {
/**
* Construct the structure using {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, IItemSource, UUID)}
*
* @return -1 if done, otherwise number of elements placed this round
*/
int survivalConstruct(ItemStack stackSize, int elementBudget, IItemSource source, UUID actorProfile);
}
@@ -2,9 +2,11 @@ package com.gtnewhorizon.structurelib.item;
import com.gtnewhorizon.structurelib.StructureLib;
import com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import java.util.List;
@@ -34,4 +36,14 @@ public class ItemConstructableTrigger extends Item {
aList.add(BLUE + translateToLocal("item.structurelib.constructableTrigger.desc.3"));//(Sneak Use in creative to build)
aList.add(BLUE + translateToLocal("item.structurelib.constructableTrigger.desc.4"));//Quantity affects tier/mode/type
}
@Override
public void onUpdate(ItemStack p_77663_1_, World p_77663_2_, Entity p_77663_3_, int p_77663_4_, boolean p_77663_5_) {
if (p_77663_1_.hasTagCompound() && p_77663_1_.getTagCompound().getLong("LastUse") + 5 < StructureLib.getOverworldTime()) {
NBTTagCompound tag = p_77663_1_.getTagCompound();
tag.removeTag("LastUse");
if (tag.hasNoTags())
p_77663_1_.setTagCompound(null);
}
}
}
@@ -0,0 +1,66 @@
package com.gtnewhorizon.structurelib.net;
import com.gtnewhorizon.structurelib.StructureLib;
import com.gtnewhorizon.structurelib.StructureLibAPI;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import io.netty.buffer.ByteBuf;
import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
public class UpdateHintParticleMessage implements IMessage {
private int x;
private short y;
private int z;
private byte r;
private byte g;
private byte b;
private byte a;
public UpdateHintParticleMessage() {
}
public UpdateHintParticleMessage(int x, short y, int z, byte r, byte g, byte b, byte a) {
this.x = x;
this.y = y;
this.z = z;
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
@Override
public void fromBytes(ByteBuf buf) {
x = buf.readInt();
y = buf.readShort();
z = buf.readInt();
r = buf.readByte();
g = buf.readByte();
b = buf.readByte();
a = buf.readByte();
}
@Override
public void toBytes(ByteBuf buf) {
buf.writeInt(x);
buf.writeShort(y);
buf.writeInt(z);
buf.writeByte(r);
buf.writeByte(g);
buf.writeByte(b);
buf.writeByte(a);
}
public static class Handler implements IMessageHandler<UpdateHintParticleMessage, IMessage> {
@Override
public IMessage onMessage(UpdateHintParticleMessage msg, MessageContext ctx) {
boolean updateResult = StructureLibAPI.updateHintParticleTint(StructureLib.getCurrentPlayer().worldObj,
msg.x, msg.y, msg.z, new short[]{msg.r, msg.g, msg.b, msg.a,});
if (!updateResult)
LOGGER.debug("Server instructed to update hint particle at ({}, {}, {}) but there is nothing there!", msg.x, msg.y, msg.z);
return null;
}
}
}
@@ -4,14 +4,13 @@ import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.gtnewhorizon.structurelib.ConfigurationHandler;
import com.gtnewhorizon.structurelib.entity.fx.EntityFXBlockHint;
import com.gtnewhorizon.structurelib.entity.fx.WeightlessParticleFX;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
@@ -23,8 +22,6 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import static com.gtnewhorizon.structurelib.StructureLib.RANDOM;
public class ClientProxy extends CommonProxy {
private static final short[] NO_TINT = {255, 255, 255, 0};
@@ -66,6 +63,17 @@ public class ClientProxy extends CommonProxy {
hintParticleTinted(w, x, y, z, createIIconFromBlock(block, meta), NO_TINT);
}
@Override
public boolean updateHintParticleTint(World w, int x, int y, int z, short[] rgBa) {
HintParticleInfo info = new HintParticleInfo(x, y, z, null);
EntityFXBlockHint existing = allHints.inverse().get(info);
if (existing != null) {
existing.withColorTint(rgBa);
return true;
}
return false;
}
private static IIcon[] createIIconFromBlock(Block block, int meta) {
IIcon[] ret = new IIcon[6];
for (int i = 0; i < 6; i++) {
@@ -142,6 +150,12 @@ public class ClientProxy extends CommonProxy {
MinecraftForge.EVENT_BUS.register(new ForgeEventHandler());
}
@Override
public long getOverworldTime() {
// there is no overworld, better just hope current world time is ok...
return Minecraft.getMinecraft().theWorld.getTotalWorldTime();
}
private static class HintParticleInfo {
private final int x, y, z;
private final List<EntityFXBlockHint> owner;
@@ -3,6 +3,7 @@ package com.gtnewhorizon.structurelib.proxy;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
@@ -19,6 +20,10 @@ public class CommonProxy {
public void hintParticle(World w, int x, int y, int z, Block block, int meta) {
}
public boolean updateHintParticleTint(World w, int x, int y, int z, short[] rgBa) {
return true;
}
public EntityPlayer getCurrentPlayer() {
return null;
}
@@ -38,4 +43,8 @@ public class CommonProxy {
public void preInit(FMLPreInitializationEvent e) {
}
public long getOverworldTime() {
return MinecraftServer.getServer().getEntityWorld().getTotalWorldTime();
}
}
@@ -0,0 +1,38 @@
package com.gtnewhorizon.structurelib.structure;
import com.gtnewhorizon.structurelib.util.InventoryIterable;
import com.gtnewhorizon.structurelib.util.InventoryUtility;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import java.util.function.Predicate;
public interface IItemSource {
int take(Predicate<ItemStack> predicate, boolean simulate, int count);
default boolean takeOne(Predicate<ItemStack> predicate, boolean simulate) {
return take(predicate, simulate, 1) == 1;
}
default boolean takeAll(Predicate<ItemStack> predicate, boolean simulate, int count) {
// fast path for 1 item take requests
if (count == 1) return takeOne(predicate, simulate);
int have = take(predicate, true, count);
if (have < count) return false;
take(predicate, simulate, count);
return true;
}
static IItemSource fromPlayer(EntityPlayerMP player) {
return (p, s, c) -> InventoryUtility.takeFromInventory(player, p, s, c);
}
static IItemSource fromPlayer(EntityPlayerMP player, int except) {
return (p, s, c) -> InventoryUtility.takeFromInventory(player, p, s, c);
}
static IItemSource fromInventory(IInventory inv) {
return (p, s, c) -> InventoryUtility.takeFromInventory(new InventoryIterable(inv), p, s, c);
}
}
@@ -0,0 +1,7 @@
package com.gtnewhorizon.structurelib.structure;
import net.minecraft.block.Block;
public interface ISpecialItemBlock {
int getItemMetaFromBlockMeta(Block block, int blockMeta);
}
@@ -6,6 +6,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import java.util.Arrays;
import java.util.UUID;
import static com.gtnewhorizon.structurelib.StructureLib.DEBUG_MODE;
@@ -51,6 +52,26 @@ public interface IStructureDefinition<T> {
basePositionA, basePositionB, basePositionC, hintsOnly, null);
}
/**
* @param elementBudget build up to this many elements
* @param source from where to drain resource
* @param actorProfile 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
* @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, IItemSource source, UUID actorProfile, boolean check) {
SurvivalBuildStructureWalker<T> walker = new SurvivalBuildStructureWalker<>(object, trigger, source, actorProfile, elementBudget, check);
StructureUtility.iterateV2(getStructureFor(piece), world, extendedFacing, basePositionX, basePositionY, basePositionZ,
basePositionA, basePositionB, basePositionC, walker, "iterateV2");
return walker.getBuilt();
}
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,
@@ -1,8 +1,15 @@
package com.gtnewhorizon.structurelib.structure;
import com.gtnewhorizon.structurelib.StructureLibAPI;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import java.util.UUID;
import static com.gtnewhorizon.structurelib.StructureLib.DEBUG_MODE;
import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
import static com.gtnewhorizon.structurelib.StructureLib.PANIC_MODE;
/**
* Use StructureUtility to instantiate
*/
@@ -13,6 +20,22 @@ public interface IStructureElement<T> {
boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger);
/**
* Try place the block by taking resource from given IItemSource.
*
* @param s drain resources from this place
* @param actorProfile source of action.
*/
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (PANIC_MODE)
throw new RuntimeException("Panic Tripwire hit");
if (DEBUG_MODE)
LOGGER.error("Default implementation of survivalPlaceBlock hit! Things aren't going to work well! IStructureElement class: {}", getClass().getName());
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actorProfile))
return PlaceResult.REJECT;
return PlaceResult.SKIP;
}
default int getStepA() {
return 1;
}
@@ -40,4 +63,31 @@ public interface IStructureElement<T> {
default boolean isNavigating() {
return false;
}
enum PlaceResult {
/**
* This element either exists already, or does not yet have an implementation for survivalPlaceBlock, or
* some other unforeseen situations.
*/
SKIP,
/**
* This element's space is occupied by other stuff and require player attention, or player missing required resource,
* or the block cannot be placed due to obscure mechanisms, or some other unforeseen situations.
*/
REJECT,
/**
* Autoplace cannot proceed within this tick. To proceed further would require stopping the placement and wait for next round.
*/
STOP,
/**
* Element placed successfully.
*/
ACCEPT,
/**
* Combination of ACCEPT and STOP.
*
* Element placed successfully. To proceed further would require stopping the placement and wait for next round.
*/
ACCEPT_STOP;
}
}
@@ -3,6 +3,8 @@ package com.gtnewhorizon.structurelib.structure;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import java.util.UUID;
/**
* Use StructureUtility to instantiate
*/
@@ -38,4 +40,14 @@ public interface IStructureElementChain<T> extends IStructureElement<T> {
}
return false;
}
@Override
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
for (IStructureElement<T> fallback : fallbacks()) {
PlaceResult result = fallback.survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
if (result != PlaceResult.SKIP)
return result;
}
return PlaceResult.SKIP;
}
}
@@ -3,6 +3,8 @@ package com.gtnewhorizon.structurelib.structure;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import java.util.UUID;
public interface IStructureElementCheckOnly<T> extends IStructureElement<T> {
@Override
default boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
@@ -13,4 +15,9 @@ public interface IStructureElementCheckOnly<T> extends IStructureElement<T> {
default boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
return false;
}
@Override
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return PlaceResult.SKIP;
}
}
@@ -3,9 +3,16 @@ package com.gtnewhorizon.structurelib.structure;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import java.util.UUID;
public interface IStructureElementNoPlacement<T> extends IStructureElement<T> {
@Override
default boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
return false;
}
@Override
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return PlaceResult.SKIP;
}
}
@@ -3,6 +3,8 @@ package com.gtnewhorizon.structurelib.structure;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import java.util.UUID;
/**
* Use StructureUtility to instantiate
*/
@@ -22,6 +24,11 @@ interface IStructureNavigate<T> extends IStructureElement<T> {
return true;
}
@Override
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return PlaceResult.SKIP;
}
default boolean isNavigating() {
return true;
}
@@ -0,0 +1,7 @@
package com.gtnewhorizon.structurelib.structure;
import net.minecraft.world.World;
public interface IStructureWalker<T> {
boolean visit(IStructureElement<T> element, World world, int x, int y, int z);
}
@@ -3,6 +3,7 @@ package com.gtnewhorizon.structurelib.structure;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import java.util.UUID;
import java.util.function.Function;
class LazyStructureElement<T> implements IStructureElementDeferred<T> {
@@ -35,4 +36,9 @@ class LazyStructureElement<T> implements IStructureElementDeferred<T> {
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
return get(t).spawnHint(t, world, x, y, z, trigger);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return get(t).survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
}
@@ -1,13 +1,17 @@
package com.gtnewhorizon.structurelib.structure;
import com.gtnewhorizon.structurelib.StructureLib;
import com.gtnewhorizon.structurelib.StructureLibAPI;
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
import com.gtnewhorizon.structurelib.structure.IStructureElement.PlaceResult;
import com.gtnewhorizon.structurelib.structure.adders.IBlockAdder;
import com.gtnewhorizon.structurelib.structure.adders.ITileAdder;
import com.gtnewhorizon.structurelib.util.ItemStackPredicate;
import com.gtnewhorizon.structurelib.util.Vec3Impl;
import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.IIcon;
@@ -16,19 +20,10 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
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;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.*;
import java.util.function.*;
import static com.gtnewhorizon.structurelib.StructureLib.DEBUG_MODE;
import static java.lang.Integer.MIN_VALUE;
/**
@@ -58,7 +53,17 @@ public class StructureUtility {
world.setBlock(x, y, z, Blocks.air, 0, 2);
return false;
}
@Override
public PlaceResult survivalPlaceBlock(Object o, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(o, world, x, y, z)) return PlaceResult.ACCEPT;
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actorProfile))
return PlaceResult.REJECT;
world.setBlock(x, y, z, Blocks.air, 0, 2);
return PlaceResult.ACCEPT;
}
};
@SuppressWarnings("rawtypes")
private static final IStructureElement NOT_AIR = new IStructureElement() {
@Override
@@ -77,7 +82,19 @@ public class StructureUtility {
world.setBlock(x, y, z, StructureLibAPI.getBlockHint(), 14, 2);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(Object o, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(o, world, x, y, z)) return PlaceResult.ACCEPT;
// user should place anything here.
// maybe make this configurable, but for now we try to take some cobble from user
if (s.take(is -> is.getItem() == Item.getItemFromBlock(Blocks.cobblestone), false, 1) == 1) {
world.setBlock(x, y, z, Blocks.cobblestone, 0, 2);
}
return PlaceResult.REJECT;
}
};
@SuppressWarnings("rawtypes")
private static final IStructureElement ERROR = new IStructureElement() {
@Override
@@ -95,12 +112,38 @@ public class StructureUtility {
public boolean placeBlock(Object o, World world, int x, int y, int z, ItemStack trigger) {
return true;
}
@Override
public PlaceResult survivalPlaceBlock(Object o, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return PlaceResult.REJECT;
}
};
private StructureUtility() {
}
/**
* This method assume block at given coord is NOT acceptable, but may or may not be trivially replaceable
*/
static PlaceResult survivalPlaceBlock(Block block, int meta, World world, int x, int y, int z, IItemSource s, UUID actorProfile) {
if (block == null)
throw new NullPointerException();
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actorProfile))
return PlaceResult.REJECT;
Item itemBlock = Item.getItemFromBlock(block);
int itemMeta = itemBlock instanceof ISpecialItemBlock ? ((ISpecialItemBlock) itemBlock).getItemMetaFromBlockMeta(block, meta) : meta;
if (!s.takeOne(ItemStackPredicate.from(itemBlock).withMeta(itemMeta), false))
return PlaceResult.REJECT;
if (block instanceof ICustomBlockSetting) {
ICustomBlockSetting block2 = (ICustomBlockSetting) block;
block2.setBlock(world, x, y, z, meta);
} else {
world.setBlock(x, y, z, block, meta, 2);
}
return PlaceResult.ACCEPT;
}
@SuppressWarnings("unchecked")
public static <T> IStructureElement<T> isAir() {
return AIR;
@@ -256,6 +299,15 @@ public class StructureUtility {
}
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
Pair<Block, Integer> hint = getHint(trigger);
if (hint == null)
return PlaceResult.REJECT; // TODO or SKIP?
return StructureUtility.survivalPlaceBlock(hint.getKey(), hint.getValue(), world, x, z, z, s, actorProfile);
}
};
}
@@ -295,6 +347,14 @@ public class StructureUtility {
world.setBlock(x, y, z, getBlock(), meta, 2);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
if (getBlock() == null)
return PlaceResult.REJECT; // TODO or SKIP?
return StructureUtility.survivalPlaceBlock(getBlock(), meta, world, x, z, z, s, actorProfile);
}
};
}
@@ -348,6 +408,14 @@ public class StructureUtility {
} else
return fallback.placeBlock(t, world, x, y, z, trigger);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
if (init())
return StructureUtility.survivalPlaceBlock(block, meta, world, x, z, z, s, actorProfile);
return fallback.survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -468,6 +536,12 @@ public class StructureUtility {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
return StructureUtility.survivalPlaceBlock(defaultBlock, defaultMeta, world, x, z, z, s, actorProfile);
}
};
} else {
return new IStructureElement<T>() {
@@ -488,6 +562,12 @@ public class StructureUtility {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
return StructureUtility.survivalPlaceBlock(defaultBlock, defaultMeta, world, x, z, z, s, actorProfile);
}
};
}
}
@@ -523,6 +603,12 @@ public class StructureUtility {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
return StructureUtility.survivalPlaceBlock(defaultBlock, defaultMeta, world, x, z, z, s, actorProfile);
}
};
} else {
return new IStructureElement<T>() {
@@ -543,6 +629,12 @@ public class StructureUtility {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
return StructureUtility.survivalPlaceBlock(defaultBlock, defaultMeta, world, x, z, z, s, actorProfile);
}
};
}
}
@@ -570,6 +662,12 @@ public class StructureUtility {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
return StructureUtility.survivalPlaceBlock(defaultBlock, defaultMeta, world, x, z, z, s, actorProfile);
}
};
} else {
return new IStructureElement<T>() {
@@ -590,6 +688,12 @@ public class StructureUtility {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
return StructureUtility.survivalPlaceBlock(defaultBlock, defaultMeta, world, x, z, z, s, actorProfile);
}
};
}
}
@@ -619,6 +723,12 @@ public class StructureUtility {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
return StructureUtility.survivalPlaceBlock(defaultBlock, defaultMeta, world, x, z, z, s, actorProfile);
}
};
} else {
return new IStructureElement<T>() {
@@ -638,6 +748,12 @@ public class StructureUtility {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (check(t, world, x, y, z)) return PlaceResult.ACCEPT;
return StructureUtility.survivalPlaceBlock(defaultBlock, defaultMeta, world, x, z, z, s, actorProfile);
}
};
}
}
@@ -687,6 +803,12 @@ public class StructureUtility {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
//TODO should we call block adder to check????
return StructureUtility.survivalPlaceBlock(defaultBlock, defaultMeta, world, x, z, z, s, actorProfile);
}
};
} else {
return new IStructureElement<T>() {
@@ -707,6 +829,12 @@ public class StructureUtility {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
//TODO should we call block adder to check????
return StructureUtility.survivalPlaceBlock(defaultBlock, defaultMeta, world, x, z, z, s, actorProfile);
}
};
}
}
@@ -780,6 +908,11 @@ public class StructureUtility {
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
return element.spawnHint(t, world, x, y, z, trigger);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return element.survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -803,6 +936,11 @@ public class StructureUtility {
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
return element.spawnHint(t, world, x, y, z, trigger);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return element.survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -812,6 +950,13 @@ public class StructureUtility {
* Enable this structure element only if given predicate returns true.
*/
public static <T> IStructureElement<T> onlyIf(Predicate<? super T> predicate, IStructureElement<? super T> downstream) {
return onlyIf(predicate, downstream, PlaceResult.SKIP);
}
/**
* Enable this structure element only if given predicate returns true.
*/
public static <T> IStructureElement<T> onlyIf(Predicate<? super T> predicate, IStructureElement<? super T> downstream, PlaceResult placeResultWhenDisabled) {
return new IStructureElement<T>() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
@@ -827,6 +972,13 @@ public class StructureUtility {
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
return predicate.test(t) && downstream.placeBlock(t, world, x, y, z, trigger);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
if (predicate.test(t))
return downstream.survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
return placeResultWhenDisabled;
}
};
}
@@ -873,6 +1025,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return elem.survivalPlaceBlock(t.getCurrentContext(), world, x, y, z, trigger, s, actorProfile);
}
};
}
//endregion
@@ -920,6 +1077,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return to.get().survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -942,6 +1104,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return to.apply(t).survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -964,6 +1131,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return map.get(keyExtractor.apply(t)).survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -986,6 +1158,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return map.getOrDefault(keyExtractor.apply(t), defaultElem).survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -1009,6 +1186,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return array[keyExtractor.apply(t)].survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -1036,6 +1218,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return to.apply(t, trigger).survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -1058,6 +1245,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return map.get(keyExtractor.apply(t, trigger)).survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -1080,6 +1272,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return map.getOrDefault(keyExtractor.apply(t, trigger), defaultElem).survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -1103,6 +1300,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return array[keyExtractor.apply(t, trigger)].survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -1130,6 +1332,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return to.apply(t, trigger).survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -1152,6 +1359,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return map.get(keyExtractor.apply(t, trigger)).survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -1174,6 +1386,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return map.getOrDefault(keyExtractor.apply(t, trigger), defaultElem).survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -1197,6 +1414,11 @@ public class StructureUtility {
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);
}
@Override
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, UUID actorProfile) {
return array[keyExtractor.apply(t, trigger)].survivalPlaceBlock(t, world, x, y, z, trigger, s, actorProfile);
}
};
}
@@ -1450,6 +1672,47 @@ public class StructureUtility {
return (builder.toString().replaceAll("\"\"", "E"));
}
static <T> boolean iterateV2(IStructureElement<T>[] elements, World world, ExtendedFacing extendedFacing,
int basePositionX, int basePositionY, int basePositionZ,
int basePositionA, int basePositionB, int basePositionC, IStructureWalker<T> predicate, String iterateType) {
//change base position to base offset
basePositionA = -basePositionA;
basePositionB = -basePositionB;
basePositionC = -basePositionC;
int[] abc = new int[]{basePositionA, basePositionB, basePositionC};
int[] xyz = new int[3];
for (IStructureElement<T> element : elements) {
if (element.isNavigating()) {
abc[0] = (element.resetA() ? basePositionA : abc[0]) + element.getStepA();
abc[1] = (element.resetB() ? basePositionB : abc[1]) + element.getStepB();
abc[2] = (element.resetC() ? basePositionC : abc[2]) + element.getStepC();
} else {
extendedFacing.getWorldOffset(abc, xyz);
xyz[0] += basePositionX;
xyz[1] += basePositionY;
xyz[2] += basePositionZ;
if (world.blockExists(xyz[0], xyz[1], xyz[2])) {
if (!predicate.visit(element, world, xyz[0], xyz[1], xyz[2])) {
if (DEBUG_MODE) {
StructureLib.LOGGER.info("Multi [{}, {}, {}] {} stop @ {} {}", basePositionX, basePositionY, basePositionZ, iterateType, Arrays.toString(xyz), Arrays.toString(abc));
}
return false;
}
} else {
if (DEBUG_MODE) {
StructureLib.LOGGER.info("Multi [{}, {}, {}] {} !blockExists @ {} {}", basePositionX, basePositionY, basePositionZ, iterateType, Arrays.toString(xyz), Arrays.toString(abc));
}
return false;
}
abc[0] += 1;
}
}
return true;
}
public static void iterate(World world, ExtendedFacing extendedFacing,
int basePositionX, int basePositionY, int basePositionZ,
int basePositionA, int basePositionB, int basePositionC,
@@ -0,0 +1,55 @@
package com.gtnewhorizon.structurelib.structure;
import com.gtnewhorizon.structurelib.structure.IStructureElement.PlaceResult;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import java.util.UUID;
class SurvivalBuildStructureWalker<T> implements IStructureWalker<T> {
private final T object;
private final ItemStack trigger;
private final IItemSource source;
private final UUID actorProfile;
private final int elementBudget;
private final boolean check;
private int built;
public SurvivalBuildStructureWalker(T object, ItemStack trigger, IItemSource source, UUID actorProfile, int elementBudget, boolean check) {
this.object = object;
this.trigger = trigger;
this.source = source;
this.actorProfile = actorProfile;
this.elementBudget = elementBudget;
this.check = check;
built = 0;
}
@Override
public boolean visit(IStructureElement<T> element, World world, int x, int y, int z) {
PlaceResult placeResult = element.survivalPlaceBlock(object, world, x, y, z, trigger, source, actorProfile);
switch (placeResult) {
case SKIP:
return true;
case ACCEPT:
if (check)
element.check(object, world, x, y, z);
return ++built < elementBudget;
case REJECT:
return false;
case ACCEPT_STOP:
if (check)
element.check(object, world, x, y, z);
built += 1;
// intentional fallthrough
case STOP:
return false;
default:
throw new NullPointerException();
}
}
public int getBuilt() {
return built;
}
}
@@ -0,0 +1,36 @@
package com.gtnewhorizon.structurelib.util;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import java.util.Iterator;
public class InventoryIterable implements Iterable<ItemStack> {
private final IInventory inv;
public InventoryIterable(IInventory inv) {
this.inv = inv;
}
@Override
public Iterator<ItemStack> iterator() {
return new Iterator<ItemStack>() {
private int ptr = 0;
@Override
public boolean hasNext() {
return ptr >= inv.getSizeInventory();
}
@Override
public ItemStack next() {
return inv.getStackInSlot(ptr++);
}
@Override
public void remove() {
inv.setInventorySlotContents(ptr - 1, null);
}
};
}
}
@@ -0,0 +1,109 @@
/**
* Copyright (c) 2022, glee8e
* This file is part of StructureLib.
* <p>
* StructureLib is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* <p>
* StructureLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* <p>
* You should have received a copy of the GNU Lesser General Public License
* along with Foobar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.gtnewhorizon.structurelib.util;
import com.gtnewhorizon.structurelib.util.ItemStackArrayIterable;
import com.gtnewhorizon.structurelib.util.SortedRegistry;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import java.util.Iterator;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.function.Predicate;
public class InventoryUtility {
private static final SortedRegistry<Function<ItemStack, Iterable<ItemStack>>> stackExtractors = new SortedRegistry<>();
/**
* The remove() of the Iterable returned must be implemented!
*/
private static final SortedRegistry<Function<EntityPlayerMP, Iterable<ItemStack>>> inventoryProviders = new SortedRegistry<>();
private static final NavigableMap<String, Function<EntityPlayerMP, Iterable<ItemStack>>> inventoryProviderRegistry = new TreeMap<>();
static {
inventoryProviders.register("5000-main-inventory", player -> new ItemStackArrayIterable(player.inventory.mainInventory));
}
/**
* take count amount of stacks that matches given filter. might take partial amount of stuff, so simulation is suggested
* if you ever need to take more than one.
*
* @param player source of stacks
* @param predicate item stack filter
* @param simulate whether to do removal
* @param count let's hope int size is enough...
* @return amount taken. never negative nor bigger than count...
*/
public static int takeFromInventory(EntityPlayerMP player, Predicate<ItemStack> predicate, boolean simulate, int count) {
int found = 0;
for (Function<EntityPlayerMP, Iterable<ItemStack>> provider : inventoryProviders) {
found += takeFromInventory(provider.apply(player), predicate, simulate, count - found);
if (found >= count)
return found;
}
return found;
}
/**
* take count amount of stacks that matches given filter. Will do 1 level of recursion to try find more stacks....
* e.g. from backpacks...
*
* @param inv source of stacks
* @param predicate item stack filter
* @param simulate whether to do removal
* @param count let's hope int size is enough...
* @return amount taken. never negative nor bigger than count...
*/
public static int takeFromInventory(Iterable<ItemStack> inv, Predicate<ItemStack> predicate, boolean simulate, int count) {
return takeFromInventory(inv, predicate, simulate, count, true);
}
private static int takeFromInventory(Iterable<ItemStack> inv, Predicate<ItemStack> predicate, boolean simulate, int count, boolean recurse) {
int found = 0;
for (Iterator<ItemStack> iterator = inv.iterator(); iterator.hasNext(); ) {
ItemStack stack = iterator.next();
// invalid stack
if (stack == null || stack.getItem() == null || stack.stackSize <= 0) continue;
if (predicate.test(stack)) {
found += stack.stackSize;
if (found > count) {
if (!simulate) {
// leave the surplus in its place
stack.stackSize = found - count;
}
return count;
}
if (!simulate)
iterator.remove();
if (found == count)
return count;
}
if (!recurse) continue;
for (Function<ItemStack, Iterable<ItemStack>> f : stackExtractors) {
Iterable<ItemStack> stacks = f.apply(stack);
if (stacks == null) continue;
found += takeFromInventory(inv, predicate, simulate, count - found, false);
if (found > count) return found;
}
}
return found;
}
}
@@ -0,0 +1,35 @@
package com.gtnewhorizon.structurelib.util;
import net.minecraft.item.ItemStack;
import java.util.Iterator;
public class ItemStackArrayIterable implements Iterable<ItemStack> {
private final ItemStack[] stacks;
public ItemStackArrayIterable(ItemStack[] stacks) {
this.stacks = stacks;
}
@Override
public Iterator<ItemStack> iterator() {
return new Iterator<ItemStack>() {
private int ptr = 0;
@Override
public boolean hasNext() {
return ptr >= stacks.length;
}
@Override
public ItemStack next() {
return stacks[ptr++];
}
@Override
public void remove() {
stacks[ptr - 1] = null;
}
};
}
}
@@ -0,0 +1,101 @@
package com.gtnewhorizon.structurelib.util;
import net.minecraft.block.Block;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
public final class ItemStackPredicate implements Predicate<ItemStack> {
public static ItemStackPredicate from(Item item) {
return new ItemStackPredicate(item);
}
public static ItemStackPredicate from(Block block) {
return new ItemStackPredicate(Item.getItemFromBlock(block));
}
private final Item item;
private int meta;
private NBTTagCompound tag;
private NBTMode mode;
private ItemStackPredicate(Item item) {
this.item = item;
}
public ItemStackPredicate withMeta(int meta) {
this.meta = meta;
return this;
}
public ItemStackPredicate withTag(NBTMode mode, NBTTagCompound tag) {
this.mode = mode;
this.tag = tag;
return this;
}
@Override
public boolean test(ItemStack itemStack) {
if (item != null) if (itemStack.getItem() != item) return false;
if (meta != -1) if (Items.feather.getDamage(itemStack) != meta) return false;
return mode.test(tag, itemStack.stackTagCompound);
}
public enum NBTMode implements BiPredicate<NBTTagCompound, NBTTagCompound> {
IGNORE {
@Override
public boolean test(NBTTagCompound lhs, NBTTagCompound rhs) {
return true;
}
},
IN {
@Override
public boolean test(NBTTagCompound lhs, NBTTagCompound rhs) {
if (lhs == null || lhs.hasNoTags()) return true;
if (rhs == null || rhs.hasNoTags()) return false;
for (String key : MiscUtils.getTagKeys(lhs)) {
if (!rhs.hasKey(key, lhs.func_150299_b(key)))
return false;
NBTBase tag = lhs.getTag(key);
if (tag instanceof NBTTagCompound) {
if (!test((NBTTagCompound) tag, rhs.getCompoundTag(key)))
return false;
} else {
if (!tag.equals(rhs.getTag(key)))
return false;
}
}
return true;
}
},
EXACT {
@Override
public boolean test(NBTTagCompound lhs, NBTTagCompound rhs) {
if (lhs != null && lhs.hasNoTags()) lhs = null;
if (rhs != null && rhs.hasNoTags()) rhs = null;
return Objects.equals(lhs, rhs);
}
},
IGNORE_KNOWN_INSIGNIFICANT_TAGS {
@Override
public boolean test(NBTTagCompound lhs, NBTTagCompound rhs) {
// fast path for empty tags
if (rhs == null || rhs.hasNoTags()) return lhs == null || lhs.hasNoTags();
// TODO make an implementation without copying a potentially huge tag
rhs = (NBTTagCompound) rhs.copy();
for (String s : KNOWN_INSIGNIFICANT_TAGS) rhs.removeTag(s);
return EXACT.test(lhs, rhs);
}
};
private static final String[] KNOWN_INSIGNIFICANT_TAGS = {
"display", // TODO expand/refine this
};
}
}
@@ -0,0 +1,17 @@
package com.gtnewhorizon.structurelib.util;
import net.minecraft.nbt.NBTTagCompound;
import java.util.Set;
/**
* not related to a certain mod!
*/
public class MiscUtils {
private MiscUtils() {}
@SuppressWarnings("unchecked")
public static Set<String> getTagKeys(NBTTagCompound tag) {
return tag.func_150296_c();
}
}
@@ -0,0 +1,58 @@
package com.gtnewhorizon.structurelib.util;
import java.util.*;
import java.util.function.Consumer;
public class SortedRegistry<V> implements Iterable<V> {
private final NavigableMap<String, V> store = new TreeMap<>();
/**
* Store stuff in an array for faster iteration access than a red black tree
*/
private ArrayList<V> baked;
public void register(String key, V val) {
if (key == null || val == null)
throw new NullPointerException();
V old = store.putIfAbsent(key, val);
if (old != null) {
throw new IllegalArgumentException("Duplicate key: " + key);
}
// TODO allow a user to edit the order with a configuration file
baked = new ArrayList<>(store.values());
}
public int size() {
return store.size();
}
public boolean isEmpty() {
return store.isEmpty();
}
public boolean containsKey(String key) {
return store.containsKey(key);
}
public boolean containsValue(V value) {
return store.containsValue(value);
}
public V get(String key) {
return store.get(key);
}
@Override
public Iterator<V> iterator() {
return baked.iterator();
}
@Override
public void forEach(Consumer<? super V> action) {
baked.forEach(action);
}
@Override
public Spliterator<V> spliterator() {
return baked.spliterator();
}
}
@@ -24,8 +24,9 @@ item.structurelib.constructableTrigger.name=Multiblock Structure Hologram Projec
item.structurelib.constructableTrigger.desc.0=Triggers Constructable Interface
item.structurelib.constructableTrigger.desc.1=Shows multiblock construction schematic,
item.structurelib.constructableTrigger.desc.2=use on the multiblock controller.
item.structurelib.constructableTrigger.desc.3=(Sneak use on controller in creative to build)
item.structurelib.constructableTrigger.desc.3=(Sneak use on controller to build)
item.structurelib.constructableTrigger.desc.4=Quantity of schematics in item stack affects tier/mode/type
item.structurelib.constructableTrigger.too_fast=Please wait %d ticks before another autoplace...
structurelib.blockhint.desc.0=Helps while building
structurelib.blockhint.0.name=Hint 1 dot
@@ -26,6 +26,7 @@ item.structurelib.constructableTrigger.desc.1=只能在多方块主机上使用
item.structurelib.constructableTrigger.desc.2=结构的示意图。 (译者注:请搭高使用)
item.structurelib.constructableTrigger.desc.3= (创造模式下潜行右键可以直接完成搭建)
item.structurelib.constructableTrigger.desc.4=此物品堆叠数量会影响显示的机器等级/模式/类型
item.structurelib.constructableTrigger.too_fast=Please wait %d ticks before another autoplace...
structurelib.blockhint.desc.0=帮助你搭建机器
structurelib.blockhint.0.name=提示方块:1号