added the offering table functionality

This commit is contained in:
Ellpeck 2018-11-20 19:59:18 +01:00
parent 9bf2d912b1
commit caf4fe9b1e
16 changed files with 252 additions and 61 deletions

View file

@ -2,6 +2,7 @@ package de.ellpeck.naturesaura;
import de.ellpeck.naturesaura.api.NaturesAuraAPI;
import de.ellpeck.naturesaura.api.aura.item.IAuraRecharge;
import de.ellpeck.naturesaura.api.recipes.ing.NBTIngredient;
import de.ellpeck.naturesaura.blocks.tiles.TileEntityImpl;
import net.minecraft.block.Block;
import net.minecraft.block.properties.IProperty;
@ -29,7 +30,6 @@ import net.minecraft.world.gen.ChunkProviderServer;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.crafting.IngredientNBT;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.items.IItemHandlerModifiable;
@ -224,19 +224,7 @@ public final class Helper {
}, () -> null);
}
public static Ingredient nbtIng(ItemStack stack) {
return new IngredientNBTPublic(stack);
}
public static Ingredient blockIng(Block block) {
return Ingredient.fromStacks(new ItemStack(block));
}
private static class IngredientNBTPublic extends IngredientNBT {
//Why is this protected in the original class, we will never know
public IngredientNBTPublic(ItemStack stack) {
super(stack);
}
}
}

View file

@ -1,9 +1,14 @@
package de.ellpeck.naturesaura;
import de.ellpeck.naturesaura.api.NaturesAuraAPI;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFlower;
import net.minecraft.block.BlockStoneBrick;
import net.minecraft.init.Blocks;
import net.minecraftforge.common.config.Config;
import net.minecraftforge.common.config.Config.Comment;
import net.minecraftforge.common.config.Config.RangeDouble;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
@Config(modid = NaturesAura.MOD_ID, category = "")
public final class ModConfig {
@ -17,8 +22,8 @@ public final class ModConfig {
@Comment("Additional conversion recipes for the Botanist's Pickaxe right click function. Each entry needs to be formatted as modid:input_block[prop1=value1,...]->modid:output_block[prop1=value1,...] where block state properties are optional")
public String[] additionalBotanistPickaxeConversions = new String[0];
@Comment("Additional blocks that the Herbivorous Absorber can consume to generate Aura. Each entry needs to be formatted as modid:block[prop1=value1,...] where block state properties are optional")
public String[] additionalHerbivorousAbsorberFlowers = new String[0];
@Comment("Additional blocks that several mechanics identify as flowers. Each entry needs to be formatted as modid:block[prop1=value1,...] where block state properties are optional")
public String[] additionalFlowers = new String[0];
@Comment("The amount of blocks that can be between two Aura Field Creators for them to be connectable and work together")
public int fieldCreatorRange = 10;
@ -45,23 +50,25 @@ public final class ModConfig {
public boolean respectVanillaParticleSettings = true;
}
public static void initOrReload() {
try {
for (String s : general.additionalBotanistPickaxeConversions) {
String[] split = s.split("->");
NaturesAuraAPI.BOTANIST_PICKAXE_CONVERSIONS.put(
Helper.getStateFromString(split[0]),
Helper.getStateFromString(split[1]));
public static void initOrReload(boolean reload) {
if (!reload) {
try {
for (String s : general.additionalBotanistPickaxeConversions) {
String[] split = s.split("->");
NaturesAuraAPI.BOTANIST_PICKAXE_CONVERSIONS.put(
Helper.getStateFromString(split[0]),
Helper.getStateFromString(split[1]));
}
} catch (Exception e) {
NaturesAura.LOGGER.warn("Error parsing additionalBotanistPickaxeConversions", e);
}
} catch (Exception e) {
NaturesAura.LOGGER.warn("Error parsing additionalBotanistPickaxeConversions", e);
}
try {
for (String s : general.additionalHerbivorousAbsorberFlowers)
NaturesAuraAPI.FLOWER_GENERATOR_BLOCKS.add(Helper.getStateFromString(s));
} catch (Exception e) {
NaturesAura.LOGGER.warn("Error parsing additionalHerbivorousAbsorberFlowers", e);
try {
for (String s : general.additionalFlowers)
NaturesAuraAPI.FLOWERS.add(Helper.getStateFromString(s));
} catch (Exception e) {
NaturesAura.LOGGER.warn("Error parsing additionalFlowers", e);
}
}
}
}

View file

@ -72,7 +72,7 @@ public final class NaturesAura {
@EventHandler
public void init(FMLInitializationEvent event) {
ModConfig.initOrReload();
ModConfig.initOrReload(false);
ModRecipes.init();
ModRegistry.init(event);
DrainSpotEffects.init();

View file

@ -8,6 +8,7 @@ import de.ellpeck.naturesaura.api.aura.type.BasicAuraType;
import de.ellpeck.naturesaura.api.aura.type.IAuraType;
import de.ellpeck.naturesaura.api.internal.StubHooks;
import de.ellpeck.naturesaura.api.recipes.AltarRecipe;
import de.ellpeck.naturesaura.api.recipes.OfferingRecipe;
import de.ellpeck.naturesaura.api.recipes.TreeRitualRecipe;
import net.minecraft.block.BlockFlower;
import net.minecraft.block.state.IBlockState;
@ -52,11 +53,18 @@ public final class NaturesAuraAPI {
*/
public static final Map<ResourceLocation, TreeRitualRecipe> TREE_RITUAL_RECIPES = new HashMap<>();
/**
* The list of all types of flowers that the flower generator can use for
* consumption. By default, all {@link BlockFlower} instances and all blocks
* specified in the config file are added
* The list of all {@link OfferingRecipe} instances which are the recipes
* used by the Offering Table. Newly created recipes can by easily added
* using {@link OfferingRecipe#register()}.
*/
public static final List<IBlockState> FLOWER_GENERATOR_BLOCKS = new ArrayList<>();
public static final Map<ResourceLocation, OfferingRecipe> OFFERING_RECIPES = new HashMap<>();
/**
* The list of all types of blocks that several mechanics in the mod use as
* flowers. Right now, this includes the Herbivorous Absorber and the
* Offering Table. By default, all {@link BlockFlower} instances and all
* blocks specified in the config file are added
*/
public static final List<IBlockState> FLOWERS = new ArrayList<>();
/**
* A map of all of the block states that the Botanist's Pickaxe can convert
* into their mossy variations. Contains mossy brick and mossy cobblestone

View file

@ -0,0 +1,27 @@
package de.ellpeck.naturesaura.api.recipes;
import de.ellpeck.naturesaura.api.NaturesAuraAPI;
import de.ellpeck.naturesaura.api.recipes.ing.AmountIngredient;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.ResourceLocation;
public class OfferingRecipe {
public final ResourceLocation name;
public final AmountIngredient input;
public final Ingredient startItem;
public final ItemStack output;
public OfferingRecipe(ResourceLocation name, AmountIngredient input, Ingredient startItem, ItemStack output) {
this.name = name;
this.input = input;
this.startItem = startItem;
this.output = output;
}
public OfferingRecipe register() {
NaturesAuraAPI.OFFERING_RECIPES.put(this.name, this);
return this;
}
}

View file

@ -0,0 +1,43 @@
package de.ellpeck.naturesaura.api.recipes.ing;
import it.unimi.dsi.fastutil.ints.IntList;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
public class AmountIngredient extends Ingredient {
public final Ingredient delegate;
public final int amount;
public AmountIngredient(Ingredient delegate, int amount) {
super(0);
this.delegate = delegate;
this.amount = amount;
}
public AmountIngredient(ItemStack stack) {
this(Ingredient.fromStacks(stack), stack.getCount());
}
@Override
public ItemStack[] getMatchingStacks() {
return this.delegate.getMatchingStacks();
}
@Override
public boolean apply(ItemStack stack) {
if (!this.delegate.apply(stack))
return false;
return stack.getCount() >= this.amount;
}
@Override
public IntList getValidItemStacksPacked() {
return this.delegate.getValidItemStacksPacked();
}
@Override
public boolean isSimple() {
return this.delegate.isSimple();
}
}

View file

@ -0,0 +1,10 @@
package de.ellpeck.naturesaura.api.recipes.ing;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.crafting.IngredientNBT;
public class NBTIngredient extends IngredientNBT {
public NBTIngredient(ItemStack stack) {
super(stack);
}
}

View file

@ -5,6 +5,7 @@ import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
public class BlockFlowerGenerator extends BlockContainerImpl {
public BlockFlowerGenerator() {
super(Material.WOOD, "flower_generator", TileEntityFlowerGenerator.class, "flower_generator");
this.setSoundType(SoundType.WOOD);

View file

@ -1,6 +1,7 @@
package de.ellpeck.naturesaura.blocks.multi;
import de.ellpeck.naturesaura.NaturesAura;
import de.ellpeck.naturesaura.api.NaturesAuraAPI;
import de.ellpeck.naturesaura.blocks.ModBlocks;
import de.ellpeck.naturesaura.blocks.multi.Multiblock.Matcher;
import net.minecraft.block.BlockLog;
@ -46,4 +47,12 @@ public final class Multiblocks {
'R', Blocks.RED_NETHER_BRICK,
'0', ModBlocks.POTION_GENERATOR,
' ', Matcher.wildcard());
public static final Multiblock OFFERING_TABLE = new Multiblock(
new ResourceLocation(NaturesAura.MOD_ID, "offering_table"),
new String[][]{
{" RRRRR ", " R R ", "R RRR R", "R R R R", "R R 0 R R", "R R R R", "R RRR R", " R R ", " RRRRR "}},
'R', new Matcher(Blocks.RED_FLOWER.getDefaultState(),
(world, start, offset, pos, state, c) -> NaturesAuraAPI.FLOWERS.contains(state)),
'0', ModBlocks.OFFERING_TABLE,
' ', Matcher.wildcard());
}

View file

@ -25,14 +25,6 @@ import java.util.Map;
public class TileEntityFlowerGenerator extends TileEntityImpl implements ITickable {
static {
for (Block block : ForgeRegistries.BLOCKS) {
if (block instanceof BlockFlower) {
NaturesAuraAPI.FLOWER_GENERATOR_BLOCKS.addAll(block.getBlockState().getValidStates());
}
}
}
private final Map<IBlockState, MutableInt> consumedRecently = new HashMap<>();
@Override
@ -44,7 +36,7 @@ public class TileEntityFlowerGenerator extends TileEntityImpl implements ITickab
for (int z = -range; z <= range; z++) {
BlockPos offset = this.pos.add(x, 0, z);
IBlockState state = this.world.getBlockState(offset);
if (NaturesAuraAPI.FLOWER_GENERATOR_BLOCKS.contains(state)) {
if (NaturesAuraAPI.FLOWERS.contains(state)) {
possible.add(offset);
}
}

View file

@ -1,18 +1,101 @@
package de.ellpeck.naturesaura.blocks.tiles;
import de.ellpeck.naturesaura.api.NaturesAuraAPI;
import de.ellpeck.naturesaura.api.recipes.OfferingRecipe;
import de.ellpeck.naturesaura.blocks.multi.Multiblocks;
import net.minecraft.entity.effect.EntityLightningBolt;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemStackHandler;
public class TileEntityOfferingTable extends TileEntityImpl {
import java.util.ArrayDeque;
import java.util.List;
import java.util.Queue;
public class TileEntityOfferingTable extends TileEntityImpl implements ITickable {
public final ItemStackHandler items = new ItemStackHandlerNA(1, this, true);
private final Queue<ItemStack> itemsToSpawn = new ArrayDeque<>();
@Override
public void update() {
if (!this.world.isRemote) {
if (this.world.getTotalWorldTime() % 20 == 0) {
if (!Multiblocks.OFFERING_TABLE.isComplete(this.world, this.pos))
return;
ItemStack stack = this.items.getStackInSlot(0);
if (stack.isEmpty())
return;
List<EntityItem> items = this.world.getEntitiesWithinAABB(EntityItem.class, new AxisAlignedBB(this.pos).grow(1));
if (items.isEmpty())
return;
OfferingRecipe recipe = getRecipe(stack);
if (recipe == null)
return;
for (EntityItem item : items) {
if (item.isDead || item.cannotPickup())
continue;
ItemStack itemStack = item.getItem();
if (itemStack.isEmpty() || itemStack.getCount() != 1)
continue;
if (!recipe.startItem.apply(itemStack))
continue;
int recipeCount = stack.getCount() / recipe.input.amount;
stack.shrink(recipeCount * recipe.input.amount);
item.setDead();
this.sendToClients();
for (int i = 0; i < recipeCount; i++)
this.itemsToSpawn.add(recipe.output.copy());
this.world.addWeatherEffect(new EntityLightningBolt(this.world, this.pos.getX(), this.pos.getY(), this.pos.getZ(), true));
break;
}
} else if (this.world.getTotalWorldTime() % 3 == 0) {
if (!this.itemsToSpawn.isEmpty())
this.world.spawnEntity(new EntityItem(
this.world,
this.pos.getX() + 0.5F + this.world.rand.nextGaussian() * 3F,
256,
this.pos.getZ() + 0.5F + this.world.rand.nextGaussian() * 3F,
this.itemsToSpawn.remove()));
}
}
}
private static OfferingRecipe getRecipe(ItemStack input) {
for (OfferingRecipe recipe : NaturesAuraAPI.OFFERING_RECIPES.values())
if (recipe.input.apply(input))
return recipe;
return null;
}
@Override
public void writeNBT(NBTTagCompound compound, SaveType type) {
super.writeNBT(compound, type);
if (type != SaveType.BLOCK) {
compound.setTag("items", this.items.serializeNBT());
if (type != SaveType.SYNC) {
NBTTagList list = new NBTTagList();
for (ItemStack stack : this.itemsToSpawn) {
list.appendTag(stack.serializeNBT());
}
compound.setTag("items_to_spawn", list);
}
}
}
@ -21,6 +104,14 @@ public class TileEntityOfferingTable extends TileEntityImpl {
super.readNBT(compound, type);
if (type != SaveType.BLOCK) {
this.items.deserializeNBT(compound.getCompoundTag("items"));
if (type != SaveType.SYNC) {
this.itemsToSpawn.clear();
NBTTagList list = compound.getTagList("items_to_spawn", 10);
for (NBTBase base : list) {
this.itemsToSpawn.add(new ItemStack((NBTTagCompound) base));
}
}
}
}
@ -28,5 +119,4 @@ public class TileEntityOfferingTable extends TileEntityImpl {
public IItemHandlerModifiable getItemHandler(EnumFacing facing) {
return this.items;
}
}

View file

@ -10,6 +10,7 @@ import de.ellpeck.naturesaura.Helper;
import de.ellpeck.naturesaura.NaturesAura;
import de.ellpeck.naturesaura.api.NaturesAuraAPI;
import de.ellpeck.naturesaura.api.recipes.AltarRecipe;
import de.ellpeck.naturesaura.api.recipes.ing.NBTIngredient;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.ResourceLocation;
import stanhebben.zenscript.annotations.ZenClass;
@ -28,7 +29,7 @@ public final class AltarTweaker {
CraftTweakerCompat.SCHEDULED_ACTIONS.add(() -> {
ResourceLocation res = new ResourceLocation(name);
return new Add(Collections.singletonMap(res, new AltarRecipe(res,
Helper.nbtIng(InputHelper.toStack(input)),
new NBTIngredient(InputHelper.toStack(input)),
InputHelper.toStack(output),
Ingredient.fromStacks(InputHelper.toStack(catalyst)),
aura, time)));

View file

@ -10,6 +10,7 @@ import de.ellpeck.naturesaura.Helper;
import de.ellpeck.naturesaura.NaturesAura;
import de.ellpeck.naturesaura.api.NaturesAuraAPI;
import de.ellpeck.naturesaura.api.recipes.TreeRitualRecipe;
import de.ellpeck.naturesaura.api.recipes.ing.NBTIngredient;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.ResourceLocation;
import stanhebben.zenscript.annotations.ZenClass;
@ -32,7 +33,7 @@ public final class TreeRitualTweaker {
Ingredient.fromStacks(InputHelper.toStack(saplingType)),
InputHelper.toStack(result),
time,
Arrays.stream(items).map(item -> Helper.nbtIng(InputHelper.toStack(item))).toArray(Ingredient[]::new)
Arrays.stream(items).map(item -> new NBTIngredient(InputHelper.toStack(item))).toArray(Ingredient[]::new)
)));
});
}

View file

@ -59,7 +59,7 @@ public class CommonEvents {
public void onConfigChanged(OnConfigChangedEvent event) {
if (NaturesAura.MOD_ID.equals(event.getModID())) {
ConfigManager.sync(NaturesAura.MOD_ID, Config.Type.INSTANCE);
ModConfig.initOrReload();
ModConfig.initOrReload(true);
}
}
}

View file

@ -29,15 +29,6 @@ import javax.annotation.Nullable;
public class ItemPickaxeNA extends ItemPickaxe implements IModItem, IModelProvider {
static {
NaturesAuraAPI.BOTANIST_PICKAXE_CONVERSIONS.put(
Blocks.COBBLESTONE.getDefaultState(),
Blocks.MOSSY_COBBLESTONE.getDefaultState());
NaturesAuraAPI.BOTANIST_PICKAXE_CONVERSIONS.put(
Blocks.STONEBRICK.getDefaultState().withProperty(BlockStoneBrick.VARIANT, BlockStoneBrick.EnumType.DEFAULT),
Blocks.STONEBRICK.getDefaultState().withProperty(BlockStoneBrick.VARIANT, BlockStoneBrick.EnumType.MOSSY));
}
private final String baseName;
public ItemPickaxeNA(String baseName, ToolMaterial material) {

View file

@ -4,15 +4,22 @@ import de.ellpeck.naturesaura.Helper;
import de.ellpeck.naturesaura.NaturesAura;
import de.ellpeck.naturesaura.api.NaturesAuraAPI;
import de.ellpeck.naturesaura.api.recipes.AltarRecipe;
import de.ellpeck.naturesaura.api.recipes.OfferingRecipe;
import de.ellpeck.naturesaura.api.recipes.TreeRitualRecipe;
import de.ellpeck.naturesaura.api.recipes.ing.AmountIngredient;
import de.ellpeck.naturesaura.api.recipes.ing.NBTIngredient;
import de.ellpeck.naturesaura.blocks.ModBlocks;
import de.ellpeck.naturesaura.items.ItemAuraBottle;
import de.ellpeck.naturesaura.items.ModItems;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFlower;
import net.minecraft.block.BlockStoneBrick;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
public final class ModRecipes {
@ -30,7 +37,7 @@ public final class ModRecipes {
Helper.blockIng(Blocks.STONE),
Ingredient.fromItem(ModItems.GOLD_LEAF),
Ingredient.fromItem(Items.GOLD_INGOT),
Helper.nbtIng(ItemAuraBottle.setType(new ItemStack(ModItems.AURA_BOTTLE), NaturesAuraAPI.TYPE_OVERWORLD))).register();
new NBTIngredient(ItemAuraBottle.setType(new ItemStack(ModItems.AURA_BOTTLE), NaturesAuraAPI.TYPE_OVERWORLD))).register();
new TreeRitualRecipe(new ResourceLocation(NaturesAura.MOD_ID, "ancient_sapling"),
Helper.blockIng(Blocks.SAPLING), new ItemStack(ModBlocks.ANCIENT_SAPLING), 200,
Helper.blockIng(Blocks.SAPLING),
@ -48,7 +55,7 @@ public final class ModRecipes {
Ingredient.fromItem(Items.FIRE_CHARGE),
Ingredient.fromItem(Items.FLINT),
Helper.blockIng(Blocks.MAGMA),
Helper.nbtIng(ItemAuraBottle.setType(new ItemStack(ModItems.AURA_BOTTLE), NaturesAuraAPI.TYPE_NETHER))).register();
new NBTIngredient(ItemAuraBottle.setType(new ItemStack(ModItems.AURA_BOTTLE), NaturesAuraAPI.TYPE_NETHER))).register();
new TreeRitualRecipe(new ResourceLocation(NaturesAura.MOD_ID, "conversion_catalyst"),
Ingredient.fromStacks(new ItemStack(Blocks.SAPLING, 1, 3)), new ItemStack(ModBlocks.CONVERSION_CATALYST), 600,
Ingredient.fromStacks(new ItemStack(Blocks.STONEBRICK, 1, 1)),
@ -69,11 +76,27 @@ public final class ModRecipes {
Ingredient.EMPTY, 150, 40).register();
new AltarRecipe(new ResourceLocation(NaturesAura.MOD_ID, "chorus"),
Helper.nbtIng(ItemAuraBottle.setType(new ItemStack(ModItems.AURA_BOTTLE), NaturesAuraAPI.TYPE_END)),
new NBTIngredient(ItemAuraBottle.setType(new ItemStack(ModItems.AURA_BOTTLE), NaturesAuraAPI.TYPE_END)),
new ItemStack(Items.DRAGON_BREATH),
Helper.blockIng(ModBlocks.CONVERSION_CATALYST), 350, 80).register();
new AltarRecipe(new ResourceLocation(NaturesAura.MOD_ID, "leather"),
Ingredient.fromItem(Items.ROTTEN_FLESH), new ItemStack(Items.LEATHER),
Helper.blockIng(ModBlocks.CONVERSION_CATALYST), 400, 50).register();
new OfferingRecipe(new ResourceLocation(NaturesAura.MOD_ID, "test"),
new AmountIngredient(new ItemStack(ModItems.INFUSED_IRON, 3)),
Ingredient.fromItem(Items.DIAMOND),
new ItemStack(Blocks.DIRT)).register();
NaturesAuraAPI.BOTANIST_PICKAXE_CONVERSIONS.put(
Blocks.COBBLESTONE.getDefaultState(),
Blocks.MOSSY_COBBLESTONE.getDefaultState());
NaturesAuraAPI.BOTANIST_PICKAXE_CONVERSIONS.put(
Blocks.STONEBRICK.getDefaultState().withProperty(BlockStoneBrick.VARIANT, BlockStoneBrick.EnumType.DEFAULT),
Blocks.STONEBRICK.getDefaultState().withProperty(BlockStoneBrick.VARIANT, BlockStoneBrick.EnumType.MOSSY));
for (Block block : ForgeRegistries.BLOCKS)
if (block instanceof BlockFlower)
NaturesAuraAPI.FLOWERS.addAll(block.getBlockState().getValidStates());
}
}