add NA's own, faster multiblock system

This commit is contained in:
Ellpeck 2018-11-07 13:33:49 +01:00
parent c6edd86fa9
commit 646395aa70
15 changed files with 317 additions and 81 deletions

View file

@ -5,7 +5,7 @@ import de.ellpeck.naturesaura.aura.chunk.AuraChunk;
import de.ellpeck.naturesaura.aura.container.IAuraContainer; import de.ellpeck.naturesaura.aura.container.IAuraContainer;
import de.ellpeck.naturesaura.aura.item.IAuraRecharge; import de.ellpeck.naturesaura.aura.item.IAuraRecharge;
import de.ellpeck.naturesaura.blocks.ModBlocks; import de.ellpeck.naturesaura.blocks.ModBlocks;
import de.ellpeck.naturesaura.blocks.Multiblocks; import de.ellpeck.naturesaura.blocks.multi.Multiblocks;
import de.ellpeck.naturesaura.commands.CommandAura; import de.ellpeck.naturesaura.commands.CommandAura;
import de.ellpeck.naturesaura.compat.Compat; import de.ellpeck.naturesaura.compat.Compat;
import de.ellpeck.naturesaura.events.CommonEvents; import de.ellpeck.naturesaura.events.CommonEvents;

View file

@ -0,0 +1,179 @@
package de.ellpeck.naturesaura.blocks.multi;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import vazkii.patchouli.api.PatchouliAPI;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
public class Multiblock {
public static final Map<ResourceLocation, Multiblock> MULTIBLOCKS = new HashMap<>();
public final ResourceLocation name;
public final Map<BlockPos, Matcher> matchers = new HashMap<>();
public final int width;
public final int height;
public final int depth;
public final int xOffset;
public final int yOffset;
public final int zOffset;
public final char[][][] rawPattern;
public Multiblock(ResourceLocation name, String[][] pattern, Object... rawMatchers) {
this.name = name;
int width = -1;
this.height = pattern.length;
int depth = -1;
int xOff = 0;
int yOff = 0;
int zOff = 0;
char[][][] raw = null;
for (int i = 0; i < pattern.length; i++) {
String[] row = pattern[i];
if (width < 0)
width = row.length;
else if (row.length != width)
throw new IllegalArgumentException();
for (int j = 0; j < row.length; j++) {
String column = row[j];
if (depth < 0)
depth = column.length();
else if (column.length() != depth)
throw new IllegalArgumentException();
if (raw == null)
raw = new char[width][this.height][depth];
for (int k = 0; k < column.length(); k++) {
char c = column.charAt(k);
raw[k][this.height - 1 - i][j] = c;
if (c == '0') {
xOff = k;
yOff = this.height - 1 - i;
zOff = j;
}
}
}
}
this.depth = depth;
this.width = width;
this.xOffset = xOff;
this.yOffset = yOff;
this.zOffset = zOff;
this.rawPattern = raw;
Map<Character, Matcher> matchers = new HashMap<>();
for (int i = 0; i < rawMatchers.length; i += 2) {
char c = (char) rawMatchers[i];
if (matchers.containsKey(c))
continue;
Object value = rawMatchers[i + 1];
if (value instanceof IBlockState)
matchers.put(c, Matcher.state((IBlockState) value));
else if (value instanceof Block)
matchers.put(c, Matcher.block((Block) value));
else
matchers.put(c, (Matcher) value);
}
for (int x = 0; x < this.width; x++)
for (int y = 0; y < this.height; y++)
for (int z = 0; z < this.depth; z++) {
Matcher matcher = matchers.get(this.rawPattern[x][y][z]);
if (matcher == null)
throw new IllegalStateException();
if (!matcher.isWildcard)
this.matchers.put(new BlockPos(x, y, z), matcher);
}
for (int i = 1; i < rawMatchers.length; i += 2) {
if (rawMatchers[i] instanceof Matcher) {
Matcher matcher = (Matcher) rawMatchers[i];
if (matcher.isWildcard)
rawMatchers[i] = PatchouliAPI.instance.anyMatcher();
else
rawMatchers[i] = PatchouliAPI.instance.predicateMatcher(matcher.defaultState,
state -> matcher.check.matches(null, null, null, null, state, (char) 0));
}
}
PatchouliAPI.instance.registerMultiblock(name, PatchouliAPI.instance.makeMultiblock(pattern, rawMatchers));
MULTIBLOCKS.put(this.name, this);
}
public boolean isComplete(World world, BlockPos center) {
BlockPos start = this.getStart(center);
return this.forEach(center, (char) 0, (pos, matcher) -> {
BlockPos offset = pos.subtract(start);
return matcher.check.matches(world, start, offset, pos, world.getBlockState(pos), this.getChar(offset));
});
}
public boolean forEach(BlockPos center, char c, BiFunction<BlockPos, Matcher, Boolean> function) {
BlockPos start = this.getStart(center);
for (Map.Entry<BlockPos, Matcher> entry : this.matchers.entrySet()) {
BlockPos offset = entry.getKey();
if (c == 0 || this.getChar(offset) == c)
if (!function.apply(start.add(offset), entry.getValue()))
return false;
}
return true;
}
public BlockPos getStart(BlockPos center) {
return center.add(-this.xOffset, -this.yOffset, -this.zOffset);
}
public char getChar(BlockPos offset) {
return this.rawPattern[offset.getX()][offset.getY()][offset.getZ()];
}
public static class Matcher {
public final IBlockState defaultState;
public final IMatcher check;
public final boolean isWildcard;
public Matcher(IBlockState defaultState, IMatcher check) {
this.defaultState = defaultState;
this.check = check;
this.isWildcard = false;
}
public Matcher(IBlockState defaultState) {
this.defaultState = defaultState;
this.check = null;
this.isWildcard = true;
}
public static Matcher state(IBlockState state) {
return new Matcher(state,
(world, start, offset, pos, other, c) -> other == state);
}
public static Matcher block(Block block) {
return new Matcher(block.getDefaultState(),
(world, start, offset, pos, state, c) -> state.getBlock() == block);
}
public static Matcher wildcard() {
return new Matcher(Blocks.AIR.getDefaultState());
}
}
public interface IMatcher {
boolean matches(World world, BlockPos start, BlockPos offset, BlockPos pos, IBlockState state, char c);
}
}

View file

@ -1,23 +1,18 @@
package de.ellpeck.naturesaura.blocks; package de.ellpeck.naturesaura.blocks.multi;
import de.ellpeck.naturesaura.NaturesAura; import de.ellpeck.naturesaura.NaturesAura;
import net.minecraft.block.Block; import de.ellpeck.naturesaura.blocks.ModBlocks;
import de.ellpeck.naturesaura.blocks.multi.Multiblock.Matcher;
import net.minecraft.block.BlockLog; import net.minecraft.block.BlockLog;
import net.minecraft.block.BlockSapling; import net.minecraft.block.BlockSapling;
import net.minecraft.block.BlockStoneBrick; import net.minecraft.block.BlockStoneBrick;
import net.minecraft.block.BlockStoneBrick.EnumType; import net.minecraft.block.BlockStoneBrick.EnumType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import vazkii.patchouli.api.IMultiblock;
import vazkii.patchouli.api.IStateMatcher;
import vazkii.patchouli.api.PatchouliAPI;
import java.util.function.Predicate;
public final class Multiblocks { public final class Multiblocks {
public static final IMultiblock ALTAR = make( public static final Multiblock ALTAR = new Multiblock(
new ResourceLocation(NaturesAura.MOD_ID, "altar"), new ResourceLocation(NaturesAura.MOD_ID, "altar"),
new String[][]{ new String[][]{
{" M ", " ", " ", " ", "M M", " ", " ", " ", " M "}, {" M ", " ", " ", " ", "M M", " ", " ", " ", " M "},
@ -29,18 +24,18 @@ public final class Multiblocks {
'W', Blocks.PLANKS, 'W', Blocks.PLANKS,
'M', Blocks.STONEBRICK.getDefaultState().withProperty(BlockStoneBrick.VARIANT, EnumType.MOSSY), 'M', Blocks.STONEBRICK.getDefaultState().withProperty(BlockStoneBrick.VARIANT, EnumType.MOSSY),
'0', ModBlocks.NATURE_ALTAR, '0', ModBlocks.NATURE_ALTAR,
' ', anyMatcher() ' ', Matcher.wildcard());
).setSymmetrical(true); public static final Multiblock TREE_RITUAL = new Multiblock(
public static final IMultiblock TREE_RITUAL = make(
new ResourceLocation(NaturesAura.MOD_ID, "tree_ritual"), new ResourceLocation(NaturesAura.MOD_ID, "tree_ritual"),
new String[][]{ new String[][]{
{" W ", " W W ", " GGG ", " GG GG ", "W G 0 G W", " GG GG ", " GGG ", " W W ", " W "}}, {" W ", " W W ", " GGG ", " GG GG ", "W G 0 G W", " GG GG ", " GGG ", " W W ", " W "}},
'W', ModBlocks.WOOD_STAND, 'W', new Matcher(ModBlocks.WOOD_STAND.getDefaultState(),
(world, start, offset, pos, state, c) -> world != null || state.getBlock() == ModBlocks.WOOD_STAND),
'G', ModBlocks.GOLD_POWDER, 'G', ModBlocks.GOLD_POWDER,
'0', matcher(Blocks.SAPLING, state -> state.getBlock() instanceof BlockSapling || state.getBlock() instanceof BlockLog), '0', new Matcher(Blocks.SAPLING.getDefaultState(),
' ', anyMatcher() (world, start, offset, pos, state, c) -> state.getBlock() instanceof BlockSapling || state.getBlock() instanceof BlockLog),
).setSymmetrical(true); ' ', Matcher.wildcard());
public static final IMultiblock POTION_GENERATOR = make( public static final Multiblock POTION_GENERATOR = new Multiblock(
new ResourceLocation(NaturesAura.MOD_ID, "potion_generator"), new ResourceLocation(NaturesAura.MOD_ID, "potion_generator"),
new String[][]{ new String[][]{
{"R R", " ", " ", " ", " ", " ", "R R"}, {"R R", " ", " ", " ", " ", " ", "R R"},
@ -50,20 +45,5 @@ public final class Multiblocks {
'N', Blocks.NETHER_BRICK, 'N', Blocks.NETHER_BRICK,
'R', Blocks.RED_NETHER_BRICK, 'R', Blocks.RED_NETHER_BRICK,
'0', ModBlocks.POTION_GENERATOR, '0', ModBlocks.POTION_GENERATOR,
' ', anyMatcher() ' ', Matcher.wildcard());
).setSymmetrical(true);
private static IStateMatcher anyMatcher() {
return PatchouliAPI.instance.anyMatcher();
}
private static IStateMatcher matcher(Block block, Predicate<IBlockState> predicate) {
return PatchouliAPI.instance.predicateMatcher(block, predicate);
}
private static IMultiblock make(ResourceLocation res, String[][] pattern, Object... targets) {
IMultiblock multi = PatchouliAPI.instance.makeMultiblock(pattern, targets);
PatchouliAPI.instance.registerMultiblock(res, multi);
return multi;
}
} }

View file

@ -5,7 +5,7 @@ import de.ellpeck.naturesaura.aura.Capabilities;
import de.ellpeck.naturesaura.aura.chunk.AuraChunk; import de.ellpeck.naturesaura.aura.chunk.AuraChunk;
import de.ellpeck.naturesaura.aura.container.BasicAuraContainer; import de.ellpeck.naturesaura.aura.container.BasicAuraContainer;
import de.ellpeck.naturesaura.aura.container.IAuraContainer; import de.ellpeck.naturesaura.aura.container.IAuraContainer;
import de.ellpeck.naturesaura.blocks.Multiblocks; import de.ellpeck.naturesaura.blocks.multi.Multiblocks;
import de.ellpeck.naturesaura.packet.PacketHandler; import de.ellpeck.naturesaura.packet.PacketHandler;
import de.ellpeck.naturesaura.packet.PacketParticleStream; import de.ellpeck.naturesaura.packet.PacketParticleStream;
import de.ellpeck.naturesaura.packet.PacketParticles; import de.ellpeck.naturesaura.packet.PacketParticles;
@ -61,7 +61,7 @@ public class TileEntityNatureAltar extends TileEntityImpl implements ITickable {
if (!this.world.isRemote) { if (!this.world.isRemote) {
if (this.world.getTotalWorldTime() % 40 == 0) { if (this.world.getTotalWorldTime() % 40 == 0) {
boolean fine = Multiblocks.ALTAR.validate(this.world, this.pos); boolean fine = Multiblocks.ALTAR.isComplete(this.world, this.pos);
if (fine != this.structureFine) { if (fine != this.structureFine) {
this.structureFine = fine; this.structureFine = fine;
this.sendToClients(); this.sendToClients();

View file

@ -1,7 +1,7 @@
package de.ellpeck.naturesaura.blocks.tiles; package de.ellpeck.naturesaura.blocks.tiles;
import de.ellpeck.naturesaura.aura.chunk.AuraChunk; import de.ellpeck.naturesaura.aura.chunk.AuraChunk;
import de.ellpeck.naturesaura.blocks.Multiblocks; import de.ellpeck.naturesaura.blocks.multi.Multiblocks;
import de.ellpeck.naturesaura.packet.PacketHandler; import de.ellpeck.naturesaura.packet.PacketHandler;
import de.ellpeck.naturesaura.packet.PacketParticles; import de.ellpeck.naturesaura.packet.PacketParticles;
import net.minecraft.entity.EntityAreaEffectCloud; import net.minecraft.entity.EntityAreaEffectCloud;
@ -22,7 +22,7 @@ public class TileEntityPotionGenerator extends TileEntityImpl implements ITickab
@Override @Override
public void update() { public void update() {
if (!this.world.isRemote && this.world.getTotalWorldTime() % 10 == 0) { if (!this.world.isRemote && this.world.getTotalWorldTime() % 10 == 0) {
if (Multiblocks.POTION_GENERATOR.validate(this.world, this.pos)) { if (Multiblocks.POTION_GENERATOR.isComplete(this.world, this.pos)) {
boolean addedOne = false; boolean addedOne = false;
List<EntityAreaEffectCloud> clouds = this.world.getEntitiesWithinAABB(EntityAreaEffectCloud.class, new AxisAlignedBB(this.pos).grow(2)); List<EntityAreaEffectCloud> clouds = this.world.getEntitiesWithinAABB(EntityAreaEffectCloud.class, new AxisAlignedBB(this.pos).grow(2));

View file

@ -1,7 +1,7 @@
package de.ellpeck.naturesaura.blocks.tiles; package de.ellpeck.naturesaura.blocks.tiles;
import de.ellpeck.naturesaura.Helper; import de.ellpeck.naturesaura.Helper;
import de.ellpeck.naturesaura.blocks.Multiblocks; import de.ellpeck.naturesaura.blocks.multi.Multiblocks;
import de.ellpeck.naturesaura.packet.PacketHandler; import de.ellpeck.naturesaura.packet.PacketHandler;
import de.ellpeck.naturesaura.packet.PacketParticleStream; import de.ellpeck.naturesaura.packet.PacketParticleStream;
import de.ellpeck.naturesaura.packet.PacketParticles; import de.ellpeck.naturesaura.packet.PacketParticles;
@ -14,11 +14,13 @@ import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.*; import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.ItemStackHandler;
import org.apache.commons.lang3.mutable.MutableBoolean;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -53,7 +55,7 @@ public class TileEntityWoodStand extends TileEntityImpl implements ITickable {
boolean isOverHalf = this.timer >= this.recipe.time / 2; boolean isOverHalf = this.timer >= this.recipe.time / 2;
if (!isOverHalf) if (!isOverHalf)
Multiblocks.TREE_RITUAL.forEach(this.world, this.ritualPos, Rotation.NONE, 'W', pos -> { Multiblocks.TREE_RITUAL.forEach(this.ritualPos, 'W', (pos, matcher) -> {
TileEntity tile = this.world.getTileEntity(pos); TileEntity tile = this.world.getTileEntity(pos);
if (tile instanceof TileEntityWoodStand && !((TileEntityWoodStand) tile).items.getStackInSlot(0).isEmpty()) { if (tile instanceof TileEntityWoodStand && !((TileEntityWoodStand) tile).items.getStackInSlot(0).isEmpty()) {
PacketHandler.sendToAllAround(this.world, this.pos, 32, new PacketParticleStream( PacketHandler.sendToAllAround(this.world, this.pos, 32, new PacketParticleStream(
@ -64,6 +66,7 @@ public class TileEntityWoodStand extends TileEntityImpl implements ITickable {
this.world.rand.nextFloat() * 0.04F + 0.04F, 0x89cc37, this.world.rand.nextFloat() * 1F + 1F this.world.rand.nextFloat() * 0.04F + 0.04F, 0x89cc37, this.world.rand.nextFloat() * 1F + 1F
)); ));
} }
return true;
}); });
PacketHandler.sendToAllAround(this.world, this.ritualPos, 32, PacketHandler.sendToAllAround(this.world, this.ritualPos, 32,
@ -71,8 +74,10 @@ public class TileEntityWoodStand extends TileEntityImpl implements ITickable {
if (this.timer >= this.recipe.time) { if (this.timer >= this.recipe.time) {
this.recurseTreeDestruction(this.ritualPos, this.ritualPos); this.recurseTreeDestruction(this.ritualPos, this.ritualPos);
Multiblocks.TREE_RITUAL.forEach(this.world, this.ritualPos, Rotation.NONE, 'G', Multiblocks.TREE_RITUAL.forEach(this.ritualPos, 'G', (pos, matcher) -> {
pos -> this.world.setBlockToAir(pos)); this.world.setBlockToAir(pos);
return true;
});
EntityItem item = new EntityItem(this.world, EntityItem item = new EntityItem(this.world,
this.ritualPos.getX() + 0.5, this.ritualPos.getY() + 4.5, this.ritualPos.getZ() + 0.5, this.ritualPos.getX() + 0.5, this.ritualPos.getY() + 4.5, this.ritualPos.getZ() + 0.5,
@ -88,7 +93,7 @@ public class TileEntityWoodStand extends TileEntityImpl implements ITickable {
this.recipe = null; this.recipe = null;
this.timer = 0; this.timer = 0;
} else if (isOverHalf && !wasOverHalf) { } else if (isOverHalf && !wasOverHalf) {
Multiblocks.TREE_RITUAL.forEach(this.world, this.ritualPos, Rotation.NONE, 'W', pos -> { Multiblocks.TREE_RITUAL.forEach(this.ritualPos, 'W', (pos, matcher) -> {
TileEntity tile = this.world.getTileEntity(pos); TileEntity tile = this.world.getTileEntity(pos);
if (tile instanceof TileEntityWoodStand) { if (tile instanceof TileEntityWoodStand) {
TileEntityWoodStand stand = (TileEntityWoodStand) tile; TileEntityWoodStand stand = (TileEntityWoodStand) tile;
@ -102,6 +107,7 @@ public class TileEntityWoodStand extends TileEntityImpl implements ITickable {
stand.sendToClients(); stand.sendToClients();
} }
} }
return true;
}); });
} }
} else { } else {
@ -135,14 +141,12 @@ public class TileEntityWoodStand extends TileEntityImpl implements ITickable {
} }
private boolean isRitualOkay() { private boolean isRitualOkay() {
if (!Multiblocks.TREE_RITUAL.forEachMatcher(this.world, this.ritualPos, Rotation.NONE, (char) 0, (start, actionPos, x, y, z, ch, matcher) -> if (!Multiblocks.TREE_RITUAL.isComplete(this.world, this.ritualPos)) {
ch == 'W' || Multiblocks.TREE_RITUAL.test(this.world, start, x, y, z, Rotation.NONE))) {
return false; return false;
} }
if (this.timer < this.recipe.time / 2) { if (this.timer < this.recipe.time / 2) {
List<ItemStack> required = new ArrayList<>(Arrays.asList(this.recipe.items)); List<ItemStack> required = new ArrayList<>(Arrays.asList(this.recipe.items));
MutableBoolean tooMuch = new MutableBoolean(); boolean fine = Multiblocks.TREE_RITUAL.forEach(this.ritualPos, 'W', (pos, matcher) -> {
Multiblocks.TREE_RITUAL.forEach(this.world, this.ritualPos, Rotation.NONE, 'W', pos -> {
TileEntity tile = this.world.getTileEntity(pos); TileEntity tile = this.world.getTileEntity(pos);
if (tile instanceof TileEntityWoodStand) { if (tile instanceof TileEntityWoodStand) {
ItemStack stack = ((TileEntityWoodStand) tile).items.getStackInSlot(0); ItemStack stack = ((TileEntityWoodStand) tile).items.getStackInSlot(0);
@ -151,12 +155,13 @@ public class TileEntityWoodStand extends TileEntityImpl implements ITickable {
if (index >= 0) { if (index >= 0) {
required.remove(index); required.remove(index);
} else { } else {
tooMuch.setTrue(); return false;
} }
} }
} }
return true;
}); });
return tooMuch.isFalse() && required.isEmpty(); return fine && required.isEmpty();
} else } else
return true; return true;
} }

View file

@ -1,19 +1,16 @@
package de.ellpeck.naturesaura.events; package de.ellpeck.naturesaura.events;
import de.ellpeck.naturesaura.Helper; import de.ellpeck.naturesaura.Helper;
import de.ellpeck.naturesaura.blocks.ModBlocks; import de.ellpeck.naturesaura.blocks.multi.Multiblocks;
import de.ellpeck.naturesaura.blocks.Multiblocks;
import de.ellpeck.naturesaura.blocks.tiles.TileEntityWoodStand; import de.ellpeck.naturesaura.blocks.tiles.TileEntityWoodStand;
import de.ellpeck.naturesaura.recipes.TreeRitualRecipe; import de.ellpeck.naturesaura.recipes.TreeRitualRecipe;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.event.terraingen.SaplingGrowTreeEvent; import net.minecraftforge.event.terraingen.SaplingGrowTreeEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.lang3.mutable.MutableObject;
import java.util.ArrayList; import java.util.ArrayList;
@ -27,18 +24,16 @@ public class TerrainGenEvents {
World world = event.getWorld(); World world = event.getWorld();
BlockPos pos = event.getPos(); BlockPos pos = event.getPos();
if (!world.isRemote) { if (!world.isRemote) {
if (Multiblocks.TREE_RITUAL.forEachMatcher(world, pos, Rotation.NONE, (char) 0, (start, actionPos, x, y, z, ch, matcher) -> if (Multiblocks.TREE_RITUAL.isComplete(world, pos)) {
ch == 'W' || Multiblocks.TREE_RITUAL.test(world, start, x, y, z, Rotation.NONE))) {
IBlockState sapling = world.getBlockState(pos); IBlockState sapling = world.getBlockState(pos);
ItemStack saplingStack = sapling.getBlock().getItem(world, pos, sapling); ItemStack saplingStack = sapling.getBlock().getItem(world, pos, sapling);
if (!saplingStack.isEmpty()) { if (!saplingStack.isEmpty()) {
for (TreeRitualRecipe recipe : TreeRitualRecipe.RECIPES.values()) { for (TreeRitualRecipe recipe : TreeRitualRecipe.RECIPES.values()) {
if (recipe.saplingType.isItemEqual(saplingStack)) { if (recipe.saplingType.isItemEqual(saplingStack)) {
List<ItemStack> required = new ArrayList<>(Arrays.asList(recipe.items)); List<ItemStack> required = new ArrayList<>(Arrays.asList(recipe.items));
MutableBoolean tooMuch = new MutableBoolean();
MutableObject<TileEntityWoodStand> toPick = new MutableObject<>(); MutableObject<TileEntityWoodStand> toPick = new MutableObject<>();
Multiblocks.TREE_RITUAL.forEach(world, pos, Rotation.NONE, 'W', tilePos -> { boolean fine = Multiblocks.TREE_RITUAL.forEach(pos, 'W', (tilePos, matcher) -> {
TileEntity tile = world.getTileEntity(tilePos); TileEntity tile = world.getTileEntity(tilePos);
if (tile instanceof TileEntityWoodStand) { if (tile instanceof TileEntityWoodStand) {
TileEntityWoodStand stand = (TileEntityWoodStand) tile; TileEntityWoodStand stand = (TileEntityWoodStand) tile;
@ -52,13 +47,14 @@ public class TerrainGenEvents {
toPick.setValue(stand); toPick.setValue(stand);
} }
} else { } else {
tooMuch.setTrue(); return false;
} }
} }
} }
return true;
}); });
if (tooMuch.isFalse() && required.isEmpty()) { if (fine && required.isEmpty()) {
toPick.getValue().setRitual(pos, recipe); toPick.getValue().setRitual(pos, recipe);
break; break;
} }

View file

@ -0,0 +1,74 @@
package de.ellpeck.naturesaura.items;
import de.ellpeck.naturesaura.blocks.multi.Multiblock;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.List;
public class ItemMultiblockMaker extends ItemImpl {
private static List<Multiblock> multiblocks;
public ItemMultiblockMaker() {
super("multiblock_maker");
}
@Override
public ActionResult<ItemStack> onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand handIn) {
ItemStack stack = playerIn.getHeldItem(handIn);
if (!worldIn.isRemote && playerIn.capabilities.isCreativeMode) {
int curr = getMultiblock(stack);
int next = (curr + 1) % multiblocks().size();
if (!stack.hasTagCompound())
stack.setTagCompound(new NBTTagCompound());
stack.getTagCompound().setInteger("multiblock", next);
}
return new ActionResult<>(EnumActionResult.SUCCESS, stack);
}
@Override
public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
if (player.capabilities.isCreativeMode) {
Multiblock multi = multiblocks().get(getMultiblock(player.getHeldItem(hand)));
if (multi == null)
return EnumActionResult.PASS;
if (!worldIn.isRemote)
multi.forEach(pos.up(), (char) 0, (blockPos, matcher) -> worldIn.setBlockState(blockPos, matcher.defaultState));
return EnumActionResult.SUCCESS;
}
return EnumActionResult.PASS;
}
@Override
public String getItemStackDisplayName(ItemStack stack) {
String name = super.getItemStackDisplayName(stack);
Multiblock multi = multiblocks().get(getMultiblock(stack));
return multi == null ? name : name + " (" + multi.name + ")";
}
private static int getMultiblock(ItemStack stack) {
if (!stack.hasTagCompound())
return 0;
return stack.getTagCompound().getInteger("multiblock");
}
private static List<Multiblock> multiblocks() {
if (multiblocks == null) {
multiblocks = new ArrayList<>();
multiblocks.addAll(Multiblock.MULTIBLOCKS.values());
}
return multiblocks;
}
}

View file

@ -25,4 +25,5 @@ public final class ModItems {
public static final Item INFUSED_SHOVEL = new ItemShovelNA("infused_iron_shovel", TOOL_MATERIAL_INFUSED_IRON); public static final Item INFUSED_SHOVEL = new ItemShovelNA("infused_iron_shovel", TOOL_MATERIAL_INFUSED_IRON);
public static final Item INFUSED_HOE = new ItemHoeNA("infused_iron_hoe", TOOL_MATERIAL_INFUSED_IRON); public static final Item INFUSED_HOE = new ItemHoeNA("infused_iron_hoe", TOOL_MATERIAL_INFUSED_IRON);
public static final Item INFUSED_SWORD = new ItemSwordNA("infused_iron_sword", TOOL_MATERIAL_INFUSED_IRON); public static final Item INFUSED_SWORD = new ItemSwordNA("infused_iron_sword", TOOL_MATERIAL_INFUSED_IRON);
public static final Item MULTIBLOCK_MAKER = new ItemMultiblockMaker();
} }

View file

@ -1,11 +1,10 @@
package de.ellpeck.naturesaura.packet; package de.ellpeck.naturesaura.packet;
import de.ellpeck.naturesaura.NaturesAura; import de.ellpeck.naturesaura.NaturesAura;
import de.ellpeck.naturesaura.blocks.Multiblocks; import de.ellpeck.naturesaura.blocks.multi.Multiblocks;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -72,7 +71,7 @@ public class PacketParticles implements IMessage {
switch (message.type) { switch (message.type) {
case 0: // Tree ritual: Gold powder case 0: // Tree ritual: Gold powder
BlockPos pos = new BlockPos(message.posX, message.posY, message.posZ); BlockPos pos = new BlockPos(message.posX, message.posY, message.posZ);
Multiblocks.TREE_RITUAL.forEach(world, pos, Rotation.NONE, 'G', dustPos -> { Multiblocks.TREE_RITUAL.forEach(pos, 'G', (dustPos, matcher) -> {
IBlockState state = world.getBlockState(dustPos); IBlockState state = world.getBlockState(dustPos);
AxisAlignedBB box = state.getBoundingBox(world, dustPos); AxisAlignedBB box = state.getBoundingBox(world, dustPos);
NaturesAura.proxy.spawnMagicParticle(world, NaturesAura.proxy.spawnMagicParticle(world,
@ -83,6 +82,7 @@ public class PacketParticles implements IMessage {
world.rand.nextFloat() * 0.01F + 0.02F, world.rand.nextFloat() * 0.01F + 0.02F,
(float) world.rand.nextGaussian() * 0.02F, (float) world.rand.nextGaussian() * 0.02F,
0xf4cb42, 2F, 50, 0F, false, true); 0xf4cb42, 2F, 50, 0F, false, true);
return true;
}); });
break; break;
case 1: // Tree ritual: Consuming item case 1: // Tree ritual: Consuming item

View file

@ -25,6 +25,8 @@ public class AltarRecipe {
this.catalyst = catalyst; this.catalyst = catalyst;
this.aura = aura; this.aura = aura;
this.time = time; this.time = time;
RECIPES.put(this.name, this);
} }
public static AltarRecipe forInput(ItemStack input) { public static AltarRecipe forInput(ItemStack input) {
@ -35,9 +37,4 @@ public class AltarRecipe {
} }
return null; return null;
} }
public AltarRecipe add() {
RECIPES.put(this.name, this);
return this;
}
} }

View file

@ -16,14 +16,14 @@ public final class ModRecipes {
new ItemStack(Items.SPIDER_EYE), new ItemStack(Items.SPIDER_EYE),
new ItemStack(Items.GOLD_INGOT), new ItemStack(Items.GOLD_INGOT),
new ItemStack(ModItems.GOLD_LEAF), new ItemStack(ModItems.GOLD_LEAF),
new ItemStack(ModItems.GOLD_LEAF)).add(); new ItemStack(ModItems.GOLD_LEAF));
new TreeRitualRecipe(new ResourceLocation(NaturesAura.MOD_ID, "nature_altar"), new TreeRitualRecipe(new ResourceLocation(NaturesAura.MOD_ID, "nature_altar"),
new ItemStack(Blocks.SAPLING), new ItemStack(ModBlocks.NATURE_ALTAR), 500, new ItemStack(Blocks.SAPLING), new ItemStack(ModBlocks.NATURE_ALTAR), 500,
new ItemStack(Blocks.STONE), new ItemStack(Blocks.STONE),
new ItemStack(Blocks.STONE), new ItemStack(Blocks.STONE),
new ItemStack(Blocks.STONE), new ItemStack(Blocks.STONE),
new ItemStack(ModItems.GOLD_LEAF), new ItemStack(ModItems.GOLD_LEAF),
new ItemStack(Items.GOLD_INGOT)).add(); new ItemStack(Items.GOLD_INGOT));
new TreeRitualRecipe(new ResourceLocation(NaturesAura.MOD_ID, "ancient_sapling"), new TreeRitualRecipe(new ResourceLocation(NaturesAura.MOD_ID, "ancient_sapling"),
new ItemStack(Blocks.SAPLING), new ItemStack(ModBlocks.ANCIENT_SAPLING), 200, new ItemStack(Blocks.SAPLING), new ItemStack(ModBlocks.ANCIENT_SAPLING), 200,
new ItemStack(Blocks.SAPLING), new ItemStack(Blocks.SAPLING),
@ -31,7 +31,7 @@ public final class ModRecipes {
new ItemStack(Blocks.RED_FLOWER), new ItemStack(Blocks.RED_FLOWER),
new ItemStack(Items.WHEAT_SEEDS), new ItemStack(Items.WHEAT_SEEDS),
new ItemStack(Items.REEDS), new ItemStack(Items.REEDS),
new ItemStack(ModItems.GOLD_LEAF)).add(); new ItemStack(ModItems.GOLD_LEAF));
new TreeRitualRecipe(new ResourceLocation(NaturesAura.MOD_ID, "furnace_heater"), new TreeRitualRecipe(new ResourceLocation(NaturesAura.MOD_ID, "furnace_heater"),
new ItemStack(Blocks.SAPLING), new ItemStack(ModBlocks.FURNACE_HEATER), 600, new ItemStack(Blocks.SAPLING), new ItemStack(ModBlocks.FURNACE_HEATER), 600,
new ItemStack(ModBlocks.INFUSED_STONE), new ItemStack(ModBlocks.INFUSED_STONE),
@ -40,7 +40,7 @@ public final class ModRecipes {
new ItemStack(ModItems.INFUSED_IRON), new ItemStack(ModItems.INFUSED_IRON),
new ItemStack(Items.FIRE_CHARGE), new ItemStack(Items.FIRE_CHARGE),
new ItemStack(Items.FLINT), new ItemStack(Items.FLINT),
new ItemStack(Blocks.MAGMA)).add(); new ItemStack(Blocks.MAGMA));
new TreeRitualRecipe(new ResourceLocation(NaturesAura.MOD_ID, "conversion_catalyst"), new TreeRitualRecipe(new ResourceLocation(NaturesAura.MOD_ID, "conversion_catalyst"),
new ItemStack(Blocks.SAPLING, 1, 3), new ItemStack(ModBlocks.CONVERSION_CATALYST), 600, new ItemStack(Blocks.SAPLING, 1, 3), new ItemStack(ModBlocks.CONVERSION_CATALYST), 600,
new ItemStack(Blocks.STONEBRICK, 1, 1), new ItemStack(Blocks.STONEBRICK, 1, 1),
@ -48,20 +48,20 @@ public final class ModRecipes {
new ItemStack(Items.BREWING_STAND), new ItemStack(Items.BREWING_STAND),
new ItemStack(Items.GOLD_INGOT), new ItemStack(Items.GOLD_INGOT),
new ItemStack(ModItems.GOLD_LEAF), new ItemStack(ModItems.GOLD_LEAF),
new ItemStack(Blocks.GLOWSTONE)).add(); new ItemStack(Blocks.GLOWSTONE));
new AltarRecipe(new ResourceLocation(NaturesAura.MOD_ID, "infused_iron"), new AltarRecipe(new ResourceLocation(NaturesAura.MOD_ID, "infused_iron"),
new ItemStack(Items.IRON_INGOT), new ItemStack(ModItems.INFUSED_IRON), new ItemStack(Items.IRON_INGOT), new ItemStack(ModItems.INFUSED_IRON),
null, 300, 80).add(); null, 300, 80);
new AltarRecipe(new ResourceLocation(NaturesAura.MOD_ID, "infused_stone"), new AltarRecipe(new ResourceLocation(NaturesAura.MOD_ID, "infused_stone"),
new ItemStack(Blocks.STONE), new ItemStack(ModBlocks.INFUSED_STONE), new ItemStack(Blocks.STONE), new ItemStack(ModBlocks.INFUSED_STONE),
null, 150, 40).add(); null, 150, 40);
new AltarRecipe(new ResourceLocation(NaturesAura.MOD_ID, "chorus"), new AltarRecipe(new ResourceLocation(NaturesAura.MOD_ID, "chorus"),
new ItemStack(Blocks.CHORUS_FLOWER), new ItemStack(Items.DRAGON_BREATH), new ItemStack(Blocks.CHORUS_FLOWER), new ItemStack(Items.DRAGON_BREATH),
ModBlocks.CONVERSION_CATALYST, 1000, 120).add(); ModBlocks.CONVERSION_CATALYST, 1000, 120);
new AltarRecipe(new ResourceLocation(NaturesAura.MOD_ID, "leather"), new AltarRecipe(new ResourceLocation(NaturesAura.MOD_ID, "leather"),
new ItemStack(Items.ROTTEN_FLESH), new ItemStack(Items.LEATHER), new ItemStack(Items.ROTTEN_FLESH), new ItemStack(Items.LEATHER),
ModBlocks.CONVERSION_CATALYST, 400, 50).add(); ModBlocks.CONVERSION_CATALYST, 400, 50);
} }
} }

View file

@ -22,10 +22,7 @@ public class TreeRitualRecipe {
this.items = items; this.items = items;
this.result = result; this.result = result;
this.time = time; this.time = time;
}
public TreeRitualRecipe add() {
RECIPES.put(this.name, this); RECIPES.put(this.name, this);
return this;
} }
} }

View file

@ -43,6 +43,7 @@ item.naturesaura.aura_cache.name=Aura Cache
item.naturesaura.color_changer.name=Bucket of Infinite Color item.naturesaura.color_changer.name=Bucket of Infinite Color
item.naturesaura.book.name=Book of Natural Aura item.naturesaura.book.name=Book of Natural Aura
item.naturesaura.shockwave_creator.name=Amulet of Wrath item.naturesaura.shockwave_creator.name=Amulet of Wrath
item.naturesaura.multiblock_maker.name=Multiblock Maker
container.naturesaura.tree_ritual.name=Ritual of the Forest container.naturesaura.tree_ritual.name=Ritual of the Forest
container.naturesaura.altar.name=Natural Altar Infusion container.naturesaura.altar.name=Natural Altar Infusion

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "minecraft:items/stick"
}
}