diff --git a/src/main/java/appeng/client/ClientHelper.java b/src/main/java/appeng/client/ClientHelper.java index 551932359..fbbb8d1c3 100644 --- a/src/main/java/appeng/client/ClientHelper.java +++ b/src/main/java/appeng/client/ClientHelper.java @@ -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) { diff --git a/src/main/java/appeng/client/render/effects/EnergyFx.java b/src/main/java/appeng/client/render/effects/EnergyFx.java index f83fb202d..2bc173935 100644 --- a/src/main/java/appeng/client/render/effects/EnergyFx.java +++ b/src/main/java/appeng/client/render/effects/EnergyFx.java @@ -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 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 { + public static class Factory implements IParticleFactory { 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; } } diff --git a/src/main/java/appeng/client/render/effects/EnergyParticleData.java b/src/main/java/appeng/client/render/effects/EnergyParticleData.java new file mode 100644 index 000000000..7492e8955 --- /dev/null +++ b/src/main/java/appeng/client/render/effects/EnergyParticleData.java @@ -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 . + */ + +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 DESERIALIZER = new IDeserializer() { + @Override + public EnergyParticleData deserialize(ParticleType 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 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()); + } + +} diff --git a/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java b/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java index 51b8a5375..f9496f885 100644 --- a/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java +++ b/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java @@ -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, 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), diff --git a/src/main/java/appeng/core/sync/packets/PacketBlockTransitionEffect.java b/src/main/java/appeng/core/sync/packets/PacketBlockTransitionEffect.java new file mode 100644 index 000000000..896c54579 --- /dev/null +++ b/src/main/java/appeng/core/sync/packets/PacketBlockTransitionEffect.java @@ -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 . + */ + +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); + } + +} diff --git a/src/main/java/appeng/core/sync/packets/PacketItemTransitionEffect.java b/src/main/java/appeng/core/sync/packets/PacketItemTransitionEffect.java new file mode 100644 index 000000000..ee7bdd2a8 --- /dev/null +++ b/src/main/java/appeng/core/sync/packets/PacketItemTransitionEffect.java @@ -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 . + */ + +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); + } + } + } + +} diff --git a/src/main/java/appeng/core/sync/packets/PacketMEFluidInventoryUpdate.java b/src/main/java/appeng/core/sync/packets/PacketMEFluidInventoryUpdate.java index 5ebf94b0c..a45e20b20 100644 --- a/src/main/java/appeng/core/sync/packets/PacketMEFluidInventoryUpdate.java +++ b/src/main/java/appeng/core/sync/packets/PacketMEFluidInventoryUpdate.java @@ -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); } } diff --git a/src/main/java/appeng/core/sync/packets/PacketTransitionEffect.java b/src/main/java/appeng/core/sync/packets/PacketTransitionEffect.java deleted file mode 100644 index dcaf02236..000000000 --- a/src/main/java/appeng/core/sync/packets/PacketTransitionEffect.java +++ /dev/null @@ -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 . - */ - -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)); - } - } -} diff --git a/src/main/java/appeng/fluids/parts/PartFluidAnnihilationPlane.java b/src/main/java/appeng/fluids/parts/PartFluidAnnihilationPlane.java index a360ca91d..8dcdfd9cf 100644 --- a/src/main/java/appeng/fluids/parts/PartFluidAnnihilationPlane.java +++ b/src/main/java/appeng/fluids/parts/PartFluidAnnihilationPlane.java @@ -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; } diff --git a/src/main/java/appeng/parts/automation/PartAnnihilationPlane.java b/src/main/java/appeng/parts/automation/PartAnnihilationPlane.java index 2bed78919..acb1010da 100644 --- a/src/main/java/appeng/parts/automation/PartAnnihilationPlane.java +++ b/src/main/java/appeng/parts/automation/PartAnnihilationPlane.java @@ -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 { + 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 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 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 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 tag = BlockTags.getCollection().getOrCreate(TAG_BLACKLIST); + return b.isIn(tag); + } + + public static boolean isItemBlacklisted(Item i) { + Tag tag = ItemTags.getCollection().getOrCreate(TAG_BLACKLIST); + return i.isIn(tag); + } + } diff --git a/src/main/resources/data/appliedenergistics2/tags/blocks/blacklisted/annihilation_plane.json b/src/main/resources/data/appliedenergistics2/tags/blocks/blacklisted/annihilation_plane.json new file mode 100644 index 000000000..096ea75d0 --- /dev/null +++ b/src/main/resources/data/appliedenergistics2/tags/blocks/blacklisted/annihilation_plane.json @@ -0,0 +1,8 @@ +{ + "values": [ + "minecraft:bedrock", + "minecraft:end_portal", + "minecraft:end_portal_frame", + "minecraft:command_block" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/appliedenergistics2/tags/items/blacklisted/annihilation_plane.json b/src/main/resources/data/appliedenergistics2/tags/items/blacklisted/annihilation_plane.json new file mode 100644 index 000000000..d6649e775 --- /dev/null +++ b/src/main/resources/data/appliedenergistics2/tags/items/blacklisted/annihilation_plane.json @@ -0,0 +1,4 @@ +{ + "values": [ + ] +} \ No newline at end of file