Added transporter FX in source & destination areas (wip)

This commit is contained in:
Unknown 2018-03-05 03:26:23 +01:00
parent 50812ff0d8
commit 80616c2f77
4 changed files with 385 additions and 0 deletions

View file

@ -263,6 +263,16 @@ public class TileEntityTransporter extends TileEntityAbstractEnergy implements I
transporterState = EnumTransporterState.DISABLED;
break;
}
// client effects
if ( lockStrengthActual > 0.0F
|| tickEnergizing > 0
|| tickCooldown > 0 ) {
final Entity entity = weakEntity == null ? null : weakEntity.get();
PacketHandler.sendTransporterEffectPacket(worldObj, vSource_absolute, vDestination_absolute, lockStrengthActual,
entity, v3EntityPosition,
tickEnergizing, tickCooldown, 64);
}
}
@Override

View file

@ -0,0 +1,234 @@
package cr0s.warpdrive.network;
import cr0s.warpdrive.Commons;
import cr0s.warpdrive.WarpDrive;
import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.data.Vector3;
import cr0s.warpdrive.data.VectorI;
import cr0s.warpdrive.render.EntityFXBeam;
import cr0s.warpdrive.render.EntityFXDot;
import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraftforge.common.util.ForgeDirection;
public class MessageTransporterEffect implements IMessage, IMessageHandler<MessageTransporterEffect, IMessage> {
private final int ENTITY_ID_NONE = 0;
private VectorI vSource;
private VectorI vDestination;
private double lockStrength;
private int idEntity;
private Vector3 v3EntityPosition;
private int tickEnergizing;
private int tickCooldown;
public MessageTransporterEffect() {
// required on receiving side
}
public MessageTransporterEffect(final VectorI vSource, final VectorI vDestination, final double lockStrength,
final Entity entity, final Vector3 v3EntityPosition,
final int tickEnergizing, final int tickCooldown) {
this.vSource = vSource;
this.vDestination = vDestination;
this.lockStrength = lockStrength;
this.idEntity = entity == null ? ENTITY_ID_NONE : entity.getEntityId();
this.v3EntityPosition = v3EntityPosition;
this.tickEnergizing = tickEnergizing;
this.tickCooldown = tickCooldown;
}
@Override
public void fromBytes(final ByteBuf buffer) {
int x = buffer.readInt();
int y = buffer.readInt();
int z = buffer.readInt();
vSource = new VectorI(x, y, z);
x = buffer.readInt();
y = buffer.readInt();
z = buffer.readInt();
vDestination = new VectorI(x, y, z);
lockStrength = buffer.readFloat();
idEntity = buffer.readInt();
final double xEntity = buffer.readDouble();
final double yEntity = buffer.readDouble();
final double zEntity = buffer.readDouble();
v3EntityPosition = new Vector3(xEntity, yEntity, zEntity);
tickEnergizing = buffer.readShort();
tickCooldown = buffer.readShort();
}
@Override
public void toBytes(ByteBuf buffer) {
buffer.writeInt(vSource.x);
buffer.writeInt(vSource.y);
buffer.writeInt(vSource.z);
buffer.writeInt(vDestination.x);
buffer.writeInt(vDestination.y);
buffer.writeInt(vDestination.z);
buffer.writeFloat((float) lockStrength);
buffer.writeInt(idEntity);
buffer.writeDouble(v3EntityPosition == null ? 0.0D : v3EntityPosition.x);
buffer.writeDouble(v3EntityPosition == null ? -1000.0D : v3EntityPosition.y);
buffer.writeDouble(v3EntityPosition == null ? 0.0D : v3EntityPosition.z);
buffer.writeShort(tickEnergizing);
buffer.writeShort(tickCooldown);
}
@SideOnly(Side.CLIENT)
private void handle(final World world) {
// adjust render distance
final int maxRenderDistance = Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16;
final int maxRenderDistance_squared = maxRenderDistance * maxRenderDistance;
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
// handle source
if (vSource.distance2To(player) <= maxRenderDistance_squared) {
handleAtSource(world);
}
// handle target
if (vDestination.distance2To(player) <= maxRenderDistance_squared) {
handleAtDestination(world);
}
}
private void handleAtSource(final World world) {
// add flying particles in area of effect
spawnParticlesInArea(world, vSource, false,
0.4F, 0.7F, 0.9F,
0.10F, 0.15F, 0.10F);
// get actual entity
final Entity entity = idEntity == ENTITY_ID_NONE ? null : world.getEntityByID(idEntity);
// energizing
// @TODO cylinder fade in + shower
if (entity != null) {
final Vector3 v3Position = new Vector3(entity);
final Vector3 v3Target = v3Position.clone().translate(ForgeDirection.UP, entity.height);
EntityFX effect = new EntityFXBeam(world, v3Position, v3Target,
0.6F + 0.1F * world.rand.nextFloat(),
0.6F + 0.15F * world.rand.nextFloat(),
0.8F + 0.10F * world.rand.nextFloat(),
20, 0);
FMLClientHandler.instance().getClient().effectRenderer.addEffect(effect);
}
// cooldown
// @TODO cylinder fade out
}
private void handleAtDestination(final World world) {
// add flying particles in area of effect
spawnParticlesInArea(world, vDestination, true,
0.4F, 0.9F, 0.7F,
0.10F, 0.10F, 0.15F);
// energizing
// @TODO cylinder fade in + shower
// cooldown
// @TODO cylinder fade out
}
private void spawnParticlesInArea(final World world, final VectorI vCenter, final boolean isFalling,
final float redBase, final float greenBase, final float blueBase,
final float redFactor, final float greenFactor, final float blueFactor) {
// compute area of effect
final AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox(
vCenter.x - WarpDriveConfig.TRANSPORTER_ENTITY_GRAB_RADIUS_BLOCKS,
vCenter.y - 1.0D,
vCenter.z - WarpDriveConfig.TRANSPORTER_ENTITY_GRAB_RADIUS_BLOCKS,
vCenter.x + WarpDriveConfig.TRANSPORTER_ENTITY_GRAB_RADIUS_BLOCKS + 1.0D,
vCenter.y + 2.0D,
vCenter.z + WarpDriveConfig.TRANSPORTER_ENTITY_GRAB_RADIUS_BLOCKS + 1.0D);
final Vector3 v3Motion = new Vector3(0.0D, 0.0D, 0.0D);
final Vector3 v3Acceleration = new Vector3(0.0D, isFalling ? -0.001D : 0.001D, 0.0D);
// adjust quantity to lockStrength
final int quantityInArea = (int) Commons.clamp(1, 5, Math.round(Commons.interpolate(0.2D, 1.0D, 0.8D, 5.0D, lockStrength)));
for (int count = 0; count < quantityInArea; count++) {
// start preferably from top or bottom side
double y;
if (isFalling) {
y = aabb.maxY - Math.pow(world.rand.nextDouble(), 3.0D) * (aabb.maxY - aabb.minY);
} else {
y = aabb.minY + Math.pow(world.rand.nextDouble(), 3.0D) * (aabb.maxY - aabb.minY);
}
final Vector3 v3Position = new Vector3(
aabb.minX + world.rand.nextDouble() * (aabb.maxX - aabb.minX),
y,
aabb.minZ + world.rand.nextDouble() * (aabb.maxZ - aabb.minZ));
// adjust to block presence
if ( ( isFalling && MathHelper.floor_double(y) == MathHelper.floor_double(aabb.maxY))
|| (!isFalling && MathHelper.floor_double(y) == MathHelper.floor_double(aabb.minY)) ) {
final VectorI vPosition = new VectorI(MathHelper.floor_double(v3Position.x),
MathHelper.floor_double(v3Position.y),
MathHelper.floor_double(v3Position.z));
final Block block = vPosition.getBlock(world);
if ( !block.isAir(world, vPosition.x, vPosition.y, vPosition.z)
&& block.isOpaqueCube() ) {
y += isFalling ? -1.0D : 1.0D;
v3Position.y = y;
}
}
// add particle
final EntityFX effect = new EntityFXDot(world, v3Position,
v3Motion, v3Acceleration, 0.98D,
redBase + redFactor * world.rand.nextFloat(),
greenBase+ greenFactor * world.rand.nextFloat(),
blueBase + blueFactor * world.rand.nextFloat(),
1.0F,
30);
FMLClientHandler.instance().getClient().effectRenderer.addEffect(effect);
}
}
@Override
@SideOnly(Side.CLIENT)
public IMessage onMessage(MessageTransporterEffect messageSpawnParticle, MessageContext context) {
// skip in case player just logged in
if (Minecraft.getMinecraft().theWorld == null) {
WarpDrive.logger.error("WorldObj is null, ignoring particle packet");
return null;
}
if (WarpDriveConfig.LOGGING_EFFECTS) {
WarpDrive.logger.info("Received transporter effect from %s to %s with %.3f lockStrength towards entity with id %d at %s, energizing in %d ticks, cooldown for %d ticks",
messageSpawnParticle.vSource, messageSpawnParticle.vDestination, messageSpawnParticle.lockStrength,
messageSpawnParticle.idEntity, messageSpawnParticle.v3EntityPosition,
messageSpawnParticle.tickEnergizing, messageSpawnParticle.tickCooldown);
}
messageSpawnParticle.handle(Minecraft.getMinecraft().theWorld);
return null; // no response
}
}

View file

@ -5,6 +5,7 @@ import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.data.CelestialObject;
import cr0s.warpdrive.data.CloakedArea;
import cr0s.warpdrive.data.Vector3;
import cr0s.warpdrive.data.VectorI;
import java.lang.reflect.Method;
import java.util.List;
@ -34,6 +35,7 @@ public class PacketHandler {
simpleNetworkManager.registerMessage(MessageCloak.class , MessageCloak.class , 3, Side.CLIENT);
simpleNetworkManager.registerMessage(MessageSpawnParticle.class , MessageSpawnParticle.class , 4, Side.CLIENT);
simpleNetworkManager.registerMessage(MessageVideoChannel.class , MessageVideoChannel.class , 5, Side.CLIENT);
simpleNetworkManager.registerMessage(MessageTransporterEffect.class , MessageTransporterEffect.class , 6, Side.CLIENT);
simpleNetworkManager.registerMessage(MessageTargeting.class , MessageTargeting.class , 100, Side.SERVER);
simpleNetworkManager.registerMessage(MessageClientValidation.class , MessageClientValidation.class , 101, Side.SERVER);
@ -112,6 +114,32 @@ public class PacketHandler {
}
}
// Transporter effect sent to client side
public static void sendTransporterEffectPacket(final World world, final VectorI vSource, final VectorI vDestination, final double lockStrength,
final Entity entity, final Vector3 v3EntityPosition,
final int tickEnergizing, final int tickCooldown, final int radius) {
assert(!world.isRemote);
final MessageTransporterEffect messageTransporterEffect = new MessageTransporterEffect(vSource, vDestination, lockStrength,
entity, v3EntityPosition,
tickEnergizing, tickCooldown);
// check both ends to send packet
final List<EntityPlayerMP> playerEntityList = MinecraftServer.getServer().getConfigurationManager().playerEntityList;
final int dimensionId = world.provider.dimensionId;
final int radius_square = radius * radius;
for (int index = 0; index < playerEntityList.size(); index++) {
final EntityPlayerMP entityPlayerMP = playerEntityList.get(index);
if (entityPlayerMP.dimension == dimensionId) {
if ( vSource.distance2To(entityPlayerMP) < radius_square
|| vDestination.distance2To(entityPlayerMP) < radius_square ) {
simpleNetworkManager.sendTo(messageTransporterEffect, entityPlayerMP);
}
}
}
}
// Monitor/Laser/Camera updating its video channel to client side
public static void sendVideoChannelPacket(final int dimensionId, final int xCoord, final int yCoord, final int zCoord, final int videoChannel) {
MessageVideoChannel messageVideoChannel = new MessageVideoChannel(xCoord, yCoord, zCoord, videoChannel);

View file

@ -0,0 +1,113 @@
package cr0s.warpdrive.render;
import cr0s.warpdrive.data.Vector3;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class EntityFXDot extends EntityFX {
private Vector3 v3Acceleration;
private double friction;
private int layer = 0; // 0 = particles, 1 = blocks, 2 = items
public EntityFXDot(final World world, final Vector3 v3Position,
final Vector3 v3Motion, final Vector3 v3Acceleration, final double friction,
final float red, final float green, final float blue, final float alpha,
final int age) {
super(world, v3Position.x, v3Position.y, v3Position.z, 0.0D, 0.0D, 0.0D);
this.setRBGColorF(red, green, blue);
this.setAlphaF(alpha);
this.setSize(0.02F, 0.02F);
this.noClip = true;
this.motionX = v3Motion.x;
this.motionY = v3Motion.y;
this.motionZ = v3Motion.z;
this.v3Acceleration = v3Acceleration;
this.friction = friction;
this.particleMaxAge = age;
// defaults to vanilla water drip
this.setParticleTextureIndex(113);
// refresh bounding box
setPosition(v3Position.x, v3Position.y, v3Position.z);
}
public void setParticleFromBlockIcon(final IIcon icon) {
layer = 1;
setParticleIcon(icon);
}
public void setParticleFromItemIcon(final IIcon icon) {
layer = 2;
setParticleIcon(icon);
}
@Override
public void onUpdate() {
prevPosX = posX;
prevPosY = posY;
prevPosZ = posZ;
if (particleAge++ >= particleMaxAge) {
setDead();
}
moveEntity(motionX, motionY, motionZ);
motionX = (motionX + v3Acceleration.x) * friction;
motionY = (motionY + v3Acceleration.y) * friction;
motionZ = (motionZ + v3Acceleration.z) * friction;
}
@Override
public int getFXLayer() {
return layer;
}
@Override
public void renderParticle(final Tessellator tessellator, final float partialTick,
final float cosYaw, final float cosPitch, final float sinYaw, final float sinSinPitch, final float cosSinPitch) {
double minU = particleTextureIndexX / 16.0F;
double maxU = minU + 0.0624375F;
double minV = particleTextureIndexY / 16.0F;
double maxV = minV + 0.0624375F;
final float scale = 0.1F * particleScale;
if (particleIcon != null) {
minU = particleIcon.getMinU();
maxU = particleIcon.getMaxU();
minV = particleIcon.getMinV();
maxV = particleIcon.getMaxV();
}
final double x = prevPosX + (posX - prevPosX) * partialTick - interpPosX;
final double y = prevPosY + (posY - prevPosY) * partialTick - interpPosY;
final double z = prevPosZ + (posZ - prevPosZ) * partialTick - interpPosZ;
// alpha increase during first tick and decays during last 2 ticks
float alpha = particleAlpha;
final int ageLeft = particleMaxAge - particleAge;
if (particleAge < 1) {
alpha = particleAlpha * partialTick;
} else if (ageLeft < 2) {
if (ageLeft < 1) {
alpha = particleAlpha * (0.5F - partialTick / 2.0F);
} else {
alpha = particleAlpha * (1.0F - partialTick / 2.0F);
}
}
tessellator.setColorRGBA_F(particleRed, particleGreen, particleBlue, alpha);
tessellator.addVertexWithUV(x - cosYaw * scale - sinSinPitch * scale, y - cosPitch * scale, z - sinYaw * scale - cosSinPitch * scale, maxU, maxV);
tessellator.addVertexWithUV(x - cosYaw * scale + sinSinPitch * scale, y + cosPitch * scale, z - sinYaw * scale + cosSinPitch * scale, maxU, minV);
tessellator.addVertexWithUV(x + cosYaw * scale + sinSinPitch * scale, y + cosPitch * scale, z + sinYaw * scale + cosSinPitch * scale, minU, minV);
tessellator.addVertexWithUV(x + cosYaw * scale - sinSinPitch * scale, y - cosPitch * scale, z + sinYaw * scale - cosSinPitch * scale, minU, maxV);
}
}