Fix identity annihilation plane.

Added annihilation plane blacklist tags.
Moved to using loot-table item generation for annihilation plane.
Play fluid pickup sound rather than block break sound for fluid annihilation planes.
Do not play a second block break sound (the server already does).
This commit is contained in:
Sebastian Hartte
2020-06-19 21:51:24 +02:00
parent 0a9e53d78c
commit 2458f9c890
12 changed files with 457 additions and 196 deletions
@@ -39,10 +39,7 @@ import net.minecraftforge.fml.client.registry.ClientRegistry;
import appeng.api.parts.CableRenderMode;
import appeng.block.AEBaseBlock;
import appeng.client.render.effects.EnergyFx;
import appeng.client.render.effects.LightningArcFX;
import appeng.client.render.effects.LightningFX;
import appeng.client.render.effects.VibrantFX;
import appeng.client.render.effects.*;
import appeng.core.AEConfig;
import appeng.core.AppEng;
import appeng.core.sync.network.NetworkHandler;
@@ -195,8 +192,8 @@ public class ClientHelper extends ServerHelper {
final float y = (float) (((Platform.getRandomInt() % 100) * 0.01) - 0.5) * 0.7f;
final float z = (float) (((Platform.getRandomInt() % 100) * 0.01) - 0.5) * 0.7f;
Minecraft.getInstance().particles.addParticle(EnergyFx.TYPE, posX + x, posY + y, posZ + z, -x * 0.1, -y * 0.1,
-z * 0.1);
Minecraft.getInstance().particles.addParticle(EnergyParticleData.FOR_BLOCK, posX + x, posY + y, posZ + z,
-x * 0.1, -y * 0.1, -z * 0.1);
}
private void spawnLightning(final World world, final double posX, final double posY, final double posZ) {
@@ -23,6 +23,7 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
import net.minecraft.client.particle.*;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.particles.BasicParticleType;
import net.minecraft.particles.ParticleType;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
@@ -34,7 +35,8 @@ import appeng.core.AppEng;
@OnlyIn(Dist.CLIENT)
public class EnergyFx extends SpriteTexturedParticle {
public static final BasicParticleType TYPE = new BasicParticleType(false);
public static final ParticleType<EnergyParticleData> TYPE = new ParticleType<>(false,
EnergyParticleData.DESERIALIZER);
static {
TYPE.setRegistryName(AppEng.MOD_ID, "energy_fx");
@@ -85,13 +87,6 @@ public class EnergyFx extends SpriteTexturedParticle {
}
}
public void fromItem(final AEPartLocation d) {
this.posX += 0.2 * d.xOffset;
this.posY += 0.2 * d.yOffset;
this.posZ += 0.2 * d.zOffset;
this.particleScale *= 0.8f;
}
@Override
public void tick() {
super.tick();
@@ -114,7 +109,7 @@ public class EnergyFx extends SpriteTexturedParticle {
}
@OnlyIn(Dist.CLIENT)
public static class Factory implements IParticleFactory<BasicParticleType> {
public static class Factory implements IParticleFactory<EnergyParticleData> {
private final IAnimatedSprite spriteSet;
public Factory(IAnimatedSprite spriteSet) {
@@ -122,12 +117,18 @@ public class EnergyFx extends SpriteTexturedParticle {
}
@Override
public Particle makeParticle(BasicParticleType typeIn, World worldIn, double x, double y, double z,
public Particle makeParticle(EnergyParticleData data, World worldIn, double x, double y, double z,
double xSpeed, double ySpeed, double zSpeed) {
EnergyFx result = new EnergyFx(worldIn, x, y, z, spriteSet);
result.setMotionX((float) xSpeed);
result.setMotionY((float) ySpeed);
result.setMotionZ((float) zSpeed);
if (data.forItem) {
result.posX += -0.2 * data.direction.xOffset;
result.posY += -0.2 * data.direction.yOffset;
result.posZ += -0.2 * data.direction.zOffset;
result.particleScale *= 0.8f;
}
return result;
}
}
@@ -0,0 +1,80 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 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 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.render.effects;
import java.util.Locale;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.network.PacketBuffer;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleType;
import appeng.api.util.AEPartLocation;
public class EnergyParticleData implements IParticleData {
public static final EnergyParticleData FOR_BLOCK = new EnergyParticleData(false, AEPartLocation.INTERNAL);
public final boolean forItem;
public final AEPartLocation direction;
public EnergyParticleData(boolean forItem, AEPartLocation direction) {
this.forItem = forItem;
this.direction = direction;
}
public static final IDeserializer<EnergyParticleData> DESERIALIZER = new IDeserializer<EnergyParticleData>() {
@Override
public EnergyParticleData deserialize(ParticleType<EnergyParticleData> particleTypeIn, StringReader reader)
throws CommandSyntaxException {
reader.expect(' ');
boolean forItem = reader.readBoolean();
reader.expect(' ');
AEPartLocation direction = AEPartLocation.valueOf(reader.readString().toUpperCase());
return new EnergyParticleData(forItem, direction);
}
@Override
public EnergyParticleData read(ParticleType<EnergyParticleData> particleTypeIn, PacketBuffer buffer) {
boolean forItem = buffer.readBoolean();
AEPartLocation direction = AEPartLocation.values()[buffer.readByte()];
return new EnergyParticleData(forItem, direction);
}
};
@Override
public ParticleType<?> getType() {
return EnergyFx.TYPE;
}
@Override
public void write(PacketBuffer buffer) {
buffer.writeBoolean(forItem);
buffer.writeByte((byte) direction.ordinal());
}
@Override
public String getParameters() {
return String.format(Locale.ROOT, "%s %s", forItem ? "true" : "false", direction.name().toLowerCase());
}
}
@@ -24,31 +24,7 @@ import java.util.function.Function;
import net.minecraft.network.PacketBuffer;
import appeng.core.sync.packets.PacketAssemblerAnimation;
import appeng.core.sync.packets.PacketClick;
import appeng.core.sync.packets.PacketCompassRequest;
import appeng.core.sync.packets.PacketCompassResponse;
import appeng.core.sync.packets.PacketCompressedNBT;
import appeng.core.sync.packets.PacketConfigButton;
import appeng.core.sync.packets.PacketCraftRequest;
import appeng.core.sync.packets.PacketFluidSlot;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.core.sync.packets.PacketJEIRecipe;
import appeng.core.sync.packets.PacketLightning;
import appeng.core.sync.packets.PacketMEFluidInventoryUpdate;
import appeng.core.sync.packets.PacketMEInventoryUpdate;
import appeng.core.sync.packets.PacketMatterCannon;
import appeng.core.sync.packets.PacketMockExplosion;
import appeng.core.sync.packets.PacketPaintedEntity;
import appeng.core.sync.packets.PacketPartPlacement;
import appeng.core.sync.packets.PacketPatternSlot;
import appeng.core.sync.packets.PacketProgressBar;
import appeng.core.sync.packets.PacketSwapSlots;
import appeng.core.sync.packets.PacketSwitchGuis;
import appeng.core.sync.packets.PacketTargetFluidStack;
import appeng.core.sync.packets.PacketTargetItemStack;
import appeng.core.sync.packets.PacketTransitionEffect;
import appeng.core.sync.packets.PacketValueConfig;
import appeng.core.sync.packets.*;
public class AppEngPacketHandlerBase {
private static final Map<Class<? extends AppEngPacket>, PacketTypes> REVERSE_LOOKUP = new HashMap<>();
@@ -76,7 +52,9 @@ public class AppEngPacketHandlerBase {
PACKET_VALUE_CONFIG(PacketValueConfig.class, PacketValueConfig::new),
PACKET_TRANSITION_EFFECT(PacketTransitionEffect.class, PacketTransitionEffect::new),
PACKET_ITEM_TRANSITION_EFFECT(PacketItemTransitionEffect.class, PacketItemTransitionEffect::new),
PACKET_BLOCK_TRANSITION_EFFECT(PacketBlockTransitionEffect.class, PacketBlockTransitionEffect::new),
PACKET_PROGRESS_VALUE(PacketProgressBar.class, PacketProgressBar::new),
@@ -0,0 +1,156 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 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 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.core.sync.packets;
import io.netty.buffer.Unpooled;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.SoundType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SimpleSound;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.registries.GameData;
import appeng.api.util.AEPartLocation;
import appeng.client.render.effects.EnergyParticleData;
import appeng.core.AELog;
import appeng.core.AppEng;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.util.Platform;
/**
* Plays the block breaking or fluid pickup sound and a transition particle
* effect into the supplied direction. Used primarily by annihilation planes.
*/
public class PacketBlockTransitionEffect extends AppEngPacket {
private final BlockPos pos;
private final BlockState blockState;
private final AEPartLocation direction;
private final SoundMode soundMode;
public enum SoundMode {
BLOCK, FLUID, NONE
}
public PacketBlockTransitionEffect(BlockPos pos, BlockState blockState, AEPartLocation direction,
SoundMode soundMode) {
this.pos = pos;
this.blockState = blockState;
this.direction = direction;
this.soundMode = soundMode;
final PacketBuffer data = new PacketBuffer(Unpooled.buffer());
data.writeInt(this.getPacketID());
data.writeBlockPos(pos);
int blockStateId = GameData.getBlockStateIDMap().get(blockState);
if (blockStateId == -1) {
AELog.warn("Failed to find numeric id for block state %s", blockState);
}
data.writeInt(blockStateId);
data.writeByte(this.direction.ordinal());
data.writeByte((byte) soundMode.ordinal());
this.configureWrite(data);
}
public PacketBlockTransitionEffect(final PacketBuffer stream) {
this.pos = stream.readBlockPos();
int blockStateId = stream.readInt();
BlockState blockState = GameData.getBlockStateIDMap().getByValue(blockStateId);
if (blockState == null) {
AELog.warn("Received invalid blockstate id %d from server", blockStateId);
blockState = Blocks.AIR.getDefaultState();
}
this.blockState = blockState;
this.direction = AEPartLocation.fromOrdinal(stream.readByte());
this.soundMode = SoundMode.values()[stream.readByte()];
}
@Override
@OnlyIn(Dist.CLIENT)
public void clientPacketData(final INetworkInfo network, final PlayerEntity player) {
spawnParticles();
playBreakOrPickupSound();
}
private void spawnParticles() {
EnergyParticleData data = new EnergyParticleData(false, direction);
for (int zz = 0; zz < 32; zz++) {
if (AppEng.proxy.shouldAddParticles(Platform.getRandom())) {
// Distribute the spawn point across the entire block's area
double x = pos.getX() + Platform.getRandomFloat();
double y = pos.getY() + Platform.getRandomFloat();
double z = pos.getZ() + Platform.getRandomFloat();
double speedX = 0.1f * this.direction.xOffset;
double speedY = 0.1f * this.direction.yOffset;
double speedZ = 0.1f * this.direction.zOffset;
Minecraft.getInstance().particles.addParticle(data, x, y, z, speedX, speedY, speedZ);
}
}
}
private void playBreakOrPickupSound() {
SoundEvent soundEvent;
float volume;
float pitch;
if (soundMode == SoundMode.FLUID) {
// This code is based on what BucketItem does
Fluid fluid = blockState.getFluidState().getFluid();
soundEvent = fluid.getAttributes().getFillSound();
if (soundEvent == null) {
if (fluid.isIn(FluidTags.LAVA)) {
soundEvent = SoundEvents.ITEM_BUCKET_FILL_LAVA;
} else {
soundEvent = SoundEvents.ITEM_BUCKET_FILL;
}
}
volume = 1;
pitch = 1;
} else if (soundMode == SoundMode.BLOCK) {
SoundType soundType = blockState.getSoundType();
soundEvent = soundType.getBreakSound();
volume = soundType.volume;
pitch = soundType.pitch;
} else {
return;
}
SimpleSound sound = new SimpleSound(soundEvent, SoundCategory.BLOCKS, (volume + 1.0F) / 2.0F, pitch * 0.8F,
pos);
Minecraft.getInstance().getSoundHandler().play(sound);
}
}
@@ -0,0 +1,92 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 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 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.core.sync.packets;
import io.netty.buffer.Unpooled;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import appeng.api.util.AEPartLocation;
import appeng.client.render.effects.EnergyParticleData;
import appeng.core.AppEng;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.util.Platform;
/**
* Plays a transition particle effect into the supplied direction. Used
* primarily by annihilation planes.
*/
public class PacketItemTransitionEffect extends AppEngPacket {
private final double x;
private final double y;
private final double z;
private final AEPartLocation d;
public PacketItemTransitionEffect(double x, double y, double z, AEPartLocation direction) {
this.x = x;
this.y = y;
this.z = z;
this.d = direction;
final PacketBuffer data = new PacketBuffer(Unpooled.buffer());
data.writeInt(this.getPacketID());
data.writeFloat((float) x);
data.writeFloat((float) y);
data.writeFloat((float) z);
data.writeByte(this.d.ordinal());
this.configureWrite(data);
}
public PacketItemTransitionEffect(final PacketBuffer stream) {
this.x = stream.readFloat();
this.y = stream.readFloat();
this.z = stream.readFloat();
this.d = AEPartLocation.fromOrdinal(stream.readByte());
}
@Override
@OnlyIn(Dist.CLIENT)
public void clientPacketData(final INetworkInfo network, final PlayerEntity player) {
final World world = AppEng.proxy.getWorld();
EnergyParticleData data = new EnergyParticleData(true, this.d);
for (int zz = 0; zz < 8; zz++) {
if (AppEng.proxy.shouldAddParticles(Platform.getRandom())) {
// Distribute the spawn point around the item's position
double x = this.x + Platform.getRandomFloat() * 0.5 - 0.25;
double y = this.y + Platform.getRandomFloat() * 0.5 - 0.25;
double z = this.z + Platform.getRandomFloat() * 0.5 - 0.25;
double speedX = 0.1f * this.d.xOffset;
double speedY = 0.1f * this.d.yOffset;
double speedZ = 0.1f * this.d.zOffset;
Minecraft.getInstance().particles.addParticle(data, x, y, z, speedX, speedY, speedZ);
}
}
}
}
@@ -29,7 +29,6 @@ import java.util.zip.GZIPOutputStream;
import javax.annotation.Nullable;
import appeng.fluids.client.gui.GuiFluidTerminal;
import io.netty.buffer.Unpooled;
import net.minecraft.client.Minecraft;
@@ -45,6 +44,7 @@ import appeng.api.storage.data.IAEFluidStack;
import appeng.core.AELog;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.fluids.client.gui.GuiFluidTerminal;
import appeng.fluids.util.AEFluidStack;
/**
@@ -137,9 +137,8 @@ public class PacketMEFluidInventoryUpdate extends AppEngPacket {
public void clientPacketData(final INetworkInfo network, final PlayerEntity player) {
final Screen gs = Minecraft.getInstance().currentScreen;
if( gs instanceof GuiFluidTerminal)
{
( (GuiFluidTerminal) gs ).postUpdate( this.list );
if (gs instanceof GuiFluidTerminal) {
((GuiFluidTerminal) gs).postUpdate(this.list);
}
}
@@ -1,116 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 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 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.core.sync.packets;
import io.netty.buffer.Unpooled;
import net.minecraft.block.BlockState;
import net.minecraft.block.SoundType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SimpleSound;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import appeng.api.util.AEPartLocation;
import appeng.client.render.effects.EnergyFx;
import appeng.core.AppEng;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.util.Platform;
public class PacketTransitionEffect extends AppEngPacket {
private final boolean mode;
private final double x;
private final double y;
private final double z;
private final AEPartLocation d;
public PacketTransitionEffect(final PacketBuffer stream) {
this.x = stream.readFloat();
this.y = stream.readFloat();
this.z = stream.readFloat();
this.d = AEPartLocation.fromOrdinal(stream.readByte());
this.mode = stream.readBoolean();
}
// api
public PacketTransitionEffect(final double x, final double y, final double z, final AEPartLocation dir,
final boolean wasBlock) {
this.x = x;
this.y = y;
this.z = z;
this.d = dir;
this.mode = wasBlock;
final PacketBuffer data = new PacketBuffer(Unpooled.buffer());
data.writeInt(this.getPacketID());
data.writeFloat((float) x);
data.writeFloat((float) y);
data.writeFloat((float) z);
data.writeByte(this.d.ordinal());
data.writeBoolean(wasBlock);
this.configureWrite(data);
}
@Override
@OnlyIn(Dist.CLIENT)
public void clientPacketData(final INetworkInfo network, final PlayerEntity player) {
final World world = AppEng.proxy.getWorld();
for (int zz = 0; zz < (this.mode ? 32 : 8); zz++) {
if (AppEng.proxy.shouldAddParticles(Platform.getRandom())) {
double x = this.x + (this.mode ? (Platform.getRandomInt() % 100) * 0.01
: (Platform.getRandomInt() % 100) * 0.005 - 0.25);
double y = this.y + (this.mode ? (Platform.getRandomInt() % 100) * 0.01
: (Platform.getRandomInt() % 100) * 0.005 - 0.25);
double z = this.z + (this.mode ? (Platform.getRandomInt() % 100) * 0.01
: (Platform.getRandomInt() % 100) * 0.005 - 0.25);
double speedX = -0.1f * this.d.xOffset;
double speedY = -0.1f * this.d.yOffset;
double speedZ = -0.1f * this.d.zOffset;
EnergyFx fx = (EnergyFx) Minecraft.getInstance().particles.addParticle(EnergyFx.TYPE, x, y, z, speedX,
speedY, speedZ);
// FIXME: *sigh* custom particle data for this one thing :|
if (!this.mode) {
fx.fromItem(this.d);
}
}
}
if (this.mode) {
final BlockPos pos = new BlockPos((int) this.x, (int) this.y, (int) this.z);
final BlockState state = world.getBlockState(pos);
final SoundType sound = state.getSoundType(world, pos, null);
Minecraft.getInstance().getSoundHandler()
.play(new SimpleSound(sound.getBreakSound(), SoundCategory.BLOCKS,
(sound.getVolume() + 1.0F) / 2.0F, sound.getPitch() * 0.8F, (float) this.x + 0.5F,
(float) this.y + 0.5F, (float) this.z + 0.5F));
}
}
}
@@ -44,7 +44,7 @@ import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.core.AppEng;
import appeng.core.settings.TickRates;
import appeng.core.sync.packets.PacketTransitionEffect;
import appeng.core.sync.packets.PacketBlockTransitionEffect;
import appeng.fluids.util.AEFluidStack;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
@@ -243,7 +243,8 @@ public class PartFluidAnnihilationPlane extends PartBasicState implements IGridT
true);
AppEng.proxy.sendToAllNearExcept(null, pos.getX(), pos.getY(), pos.getZ(), 64, w,
new PacketTransitionEffect(pos.getX(), pos.getY(), pos.getZ(), this.getSide(), true));
new PacketBlockTransitionEffect(pos, blockstate, this.getSide().getOpposite(),
PacketBlockTransitionEffect.SoundMode.FLUID));
return TickRateModulation.URGENT;
}
@@ -23,25 +23,27 @@ import java.util.List;
import javax.annotation.Nonnull;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.Tag;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootParameters;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.common.ToolType;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.FakePlayerFactory;
import appeng.api.AEApi;
@@ -67,7 +69,8 @@ import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.core.AppEng;
import appeng.core.settings.TickRates;
import appeng.core.sync.packets.PacketTransitionEffect;
import appeng.core.sync.packets.PacketBlockTransitionEffect;
import appeng.core.sync.packets.PacketItemTransitionEffect;
import appeng.hooks.TickHandler;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
@@ -79,6 +82,9 @@ import appeng.util.item.AEItemStack;
public class PartAnnihilationPlane extends PartBasicState implements IGridTickable, IWorldCallable<TickRateModulation> {
public static final ResourceLocation TAG_BLACKLIST = new ResourceLocation(AppEng.MOD_ID,
"blacklisted/annihilation_plane");
private static final PlaneModels MODELS = new PlaneModels("part/annihilation_plane", "part/annihilation_plane_on");
@PartModels
@@ -218,6 +224,12 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
public void onEntityCollision(final Entity entity) {
if (this.isAccepting && entity instanceof ItemEntity && entity.isAlive() && Platform.isServer()
&& this.getProxy().isActive()) {
ItemEntity itemEntity = (ItemEntity) entity;
if (isItemBlacklisted(itemEntity.getItem().getItem())) {
return;
}
boolean capture = false;
final BlockPos pos = this.getTile().getPos();
@@ -267,12 +279,12 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
}
if (capture) {
final boolean changed = this.storeEntityItem((ItemEntity) entity);
final boolean changed = this.storeEntityItem(itemEntity);
if (changed) {
AppEng.proxy.sendToAllNearExcept(null, pos.getX(), pos.getY(), pos.getZ(), 64,
this.getTile().getWorld(), new PacketTransitionEffect(entity.getPosX(), entity.getPosY(),
entity.getPosZ(), this.getSide(), false));
this.getTile().getWorld(), new PacketItemTransitionEffect(entity.getPosX(),
entity.getPosY(), entity.getPosZ(), this.getSide().getOpposite()));
}
}
}
@@ -381,7 +393,9 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
final BlockPos pos = te.getPos().offset(this.getSide().getFacing());
final IEnergyGrid energy = this.getProxy().getEnergy();
if (this.canHandleBlock(w, pos)) {
final BlockState blockState = w.getBlockState(pos);
if (this.canHandleBlock(w, pos, blockState)) {
// Query the loot-table and get a potential outcome of the loot-table evaluation
final List<ItemStack> items = this.obtainBlockDrops(w, pos);
final float requiredPower = this.calculateEnergyUsage(w, pos, items);
@@ -391,11 +405,7 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
if (hasPower && canStore) {
if (modulate) {
energy.extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG);
this.breakBlockAndStoreItems(w, pos);
AppEng.proxy.sendToAllNearExcept(null, pos.getX(), pos.getY(), pos.getZ(), 64, w,
new PacketTransitionEffect(pos.getX(), pos.getY(), pos.getZ(), this.getSide(),
true));
performBreakBlock(w, pos, blockState, energy, requiredPower, items);
} else {
this.breaking = true;
TickHandler.INSTANCE.addCallable(this.getTile().getWorld(), this);
@@ -412,6 +422,31 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
return TickRateModulation.IDLE;
}
private void performBreakBlock(ServerWorld w, BlockPos pos, BlockState blockState, IEnergyGrid energy,
float requiredPower, List<ItemStack> items) {
if (!this.breakBlockAndStoreExtraItems(w, pos)) {
// We failed to actually replace the block with air or it already was the case
return;
}
for (ItemStack item : items) {
IAEItemStack overflow = storeItemStack(item);
// If inserting the item fully was not possible, drop it as an item entity
// instead
// if the storage clears up, we'll pick it up that way
if (overflow != null) {
Platform.spawnDrops(w, pos, Collections.singletonList(overflow.createItemStack()));
}
}
energy.extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG);
AppEng.proxy.sendToAllNearExcept(null, pos.getX(), pos.getY(), pos.getZ(), 64, w,
new PacketBlockTransitionEffect(pos, blockState, this.getSide().getOpposite(),
PacketBlockTransitionEffect.SoundMode.NONE));
}
@Override
public TickingRequest getTickingRequest(final IGridNode node) {
return new TickingRequest(TickRates.AnnihilationPlane.getMin(), TickRates.AnnihilationPlane.getMax(), false,
@@ -431,36 +466,44 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
/**
* Checks if this plane can handle the block at the specific coordinates.
*/
private boolean canHandleBlock(final ServerWorld w, final BlockPos pos) {
final BlockState state = w.getBlockState(pos);
private boolean canHandleBlock(final ServerWorld w, final BlockPos pos, final BlockState state) {
if (state.isAir(w, pos)) {
return false;
}
if (isBlockBlacklisted(state.getBlock())) {
return false;
}
final Material material = state.getMaterial();
final float hardness = state.getBlockHardness(w, pos);
final boolean ignoreMaterials = material == Material.AIR || material == Material.LAVA
|| material == Material.WATER || material.isLiquid();
final boolean ignoreBlocks = state.getBlock() == Blocks.BEDROCK || state.getBlock() == Blocks.END_PORTAL
|| state.getBlock() == Blocks.END_PORTAL_FRAME || state.getBlock() == Blocks.COMMAND_BLOCK;
return !ignoreMaterials && !ignoreBlocks && hardness >= 0f && !w.isAirBlock(pos) && w.isBlockLoaded(pos)
return !ignoreMaterials && hardness >= 0f && w.isBlockLoaded(pos)
&& w.canMineBlockBody(Platform.getPlayer(w), pos);
}
protected List<ItemStack> obtainBlockDrops(final ServerWorld w, final BlockPos pos) {
final FakePlayer fakePlayer = FakePlayerFactory.getMinecraft(w);
Entity fakePlayer = FakePlayerFactory.getMinecraft(w);
final BlockState state = w.getBlockState(pos);
ItemStack harvestTool = createHarvestTool(state);
// In case the block does NOT allow us to harvest it without a tool, or the
// proper tool,
// do not return anything.
if (harvestTool == null && !state.getMaterial().isToolNotRequired()) {
return Collections.emptyList();
if (harvestTool == null) {
if (!state.getMaterial().isToolNotRequired()) {
harvestTool = ItemStack.EMPTY;
} else {
// In case the block does NOT allow us to harvest it without a tool, or the
// proper tool, do not return anything.
return Collections.emptyList();
}
}
LootContext.Builder lootContext = new LootContext.Builder(w).withRandom(w.rand)
.withParameter(LootParameters.POSITION, pos).withNullableParameter(LootParameters.TOOL, harvestTool)
.withNullableParameter(LootParameters.THIS_ENTITY, fakePlayer)
.withNullableParameter(LootParameters.BLOCK_ENTITY, w.getTileEntity(pos));
return state.getDrops(lootContext);
TileEntity te = w.getTileEntity(pos);
return Block.getDrops(state, w, pos, te, fakePlayer, harvestTool);
}
/**
@@ -511,9 +554,16 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
return canStore;
}
private void breakBlockAndStoreItems(final ServerWorld w, final BlockPos pos) {
w.destroyBlock(pos, true);
private boolean breakBlockAndStoreExtraItems(final ServerWorld w, final BlockPos pos) {
// Kill the block, but signal no drops
if (!w.destroyBlock(pos, false)) {
// The block was no longer there
return false;
}
// This handles items that do not spawn via loot-tables but rather normal block
// breaking
// i.e. our cable-buses do this (bad practice, really)
final AxisAlignedBB box = new AxisAlignedBB(pos).grow(0.2);
for (final Object ei : w.getEntitiesWithinAABB(ItemEntity.class, box)) {
if (ei instanceof ItemEntity) {
@@ -521,6 +571,7 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
this.storeEntityItem(entityItem);
}
}
return true;
}
private void refresh() {
@@ -566,4 +617,14 @@ public class PartAnnihilationPlane extends PartBasicState implements IGridTickab
}
}
public static boolean isBlockBlacklisted(Block b) {
Tag<Block> tag = BlockTags.getCollection().getOrCreate(TAG_BLACKLIST);
return b.isIn(tag);
}
public static boolean isItemBlacklisted(Item i) {
Tag<Item> tag = ItemTags.getCollection().getOrCreate(TAG_BLACKLIST);
return i.isIn(tag);
}
}