mirror of
https://github.com/GTNewHorizons/StructureLib.git
synced 2026-11-12 16:27:36 +00:00
autoplace first commit
This commit is contained in:
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);
|
||||
}
|
||||
}
|
||||
+51
-19
@@ -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());
|
||||
}
|
||||
}
|
||||
+49
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+16
@@ -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;
|
||||
}
|
||||
}
|
||||
+7
@@ -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,
|
||||
|
||||
+55
@@ -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号
|
||||
|
||||
Reference in new issue
Block a user