package com.flansmod.common.driveables; import java.util.List; import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemLead; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.DamageSource; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import com.flansmod.api.IControllable; import com.flansmod.client.FlansModClient; import com.flansmod.common.FlansMod; import com.flansmod.common.RotatedAxes; import com.flansmod.common.guns.EnumFireMode; import com.flansmod.common.guns.GunType; import com.flansmod.common.guns.ItemShootable; import com.flansmod.common.guns.ShootableType; import com.flansmod.common.network.PacketDriveableKey; import com.flansmod.common.network.PacketDriveableKeyHeld; import com.flansmod.common.network.PacketPlaySound; import com.flansmod.common.network.PacketSeatUpdates; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.tools.ItemTool; import com.flansmod.common.vector.Vector3f; public class EntitySeat extends Entity implements IControllable, IEntityAdditionalSpawnData { /** Set this to true when the client has found the parent driveable and connected them */ @SideOnly(Side.CLIENT) public boolean foundDriveable; private int driveableID; private int seatID; public EntityDriveable driveable; public float playerRoll, prevPlayerRoll; public Seat seatInfo; public boolean driver; public RotatedAxes playerLooking; public RotatedAxes prevPlayerLooking; /** A set of axes used to calculate where the player is looking, x axis is the direction of looking, y is up */ public RotatedAxes looking; /** For smooth renderering */ public RotatedAxes prevLooking; /** Delay ticker for shooting guns */ public float gunDelay; /** Minigun speed */ public float minigunSpeed; /** Minigun angle for render */ public float minigunAngle; /** Sound delay ticker for looping sounds */ public int soundDelay; public int yawSoundDelay = 0; public int pitchSoundDelay = 0; public boolean playYawSound = false; public boolean playPitchSound = false; private double playerPosX, playerPosY, playerPosZ; private float playerYaw, playerPitch; /** For smoothness */ private double prevPlayerPosX, prevPlayerPosY, prevPlayerPosZ; private float prevPlayerYaw, prevPlayerPitch; private boolean shooting; /** Default constructor for spawning client side * Should not be called server side EVER */ public EntitySeat(World world) { super(world); setSize(1F, 1F); prevLooking = new RotatedAxes(); looking = new RotatedAxes(); playerLooking = new RotatedAxes(); prevPlayerLooking = new RotatedAxes(); } /** Server side seat constructor */ public EntitySeat(World world, EntityDriveable d, int id) { this(world); driveable = d; driveableID = d.getEntityId(); seatInfo = driveable.getDriveableType().seats[id]; driver = id == 0; setPosition(d.posX, d.posY, d.posZ); playerPosX = prevPlayerPosX = posX; playerPosY = prevPlayerPosY = posY; playerPosZ = prevPlayerPosZ = posZ; looking.setAngles((seatInfo.minYaw + seatInfo.maxYaw) / 2, 0F, 0F); prevLooking.setAngles((seatInfo.minYaw + seatInfo.maxYaw) / 2, 0F, 0F); //updatePosition(); } @Override public void setPositionAndRotation2(double x, double y, double z, float yaw, float pitch, int i, boolean b) { //setPosition(x, y, z); } @Override public void onUpdate() { super.onUpdate(); //prevPosX = posX; //prevPosY = posY; //prevPosZ = posZ; //If on the client and the driveable parent has yet to be found, search for it if(worldObj.isRemote && !foundDriveable) { driveable = (EntityDriveable)worldObj.getEntityByID(driveableID); if(driveable == null) return; foundDriveable = true; driveable.seats[seatID] = this; seatInfo = driveable.getDriveableType().seats[seatID]; looking.setAngles((seatInfo.minYaw + seatInfo.maxYaw) / 2, 0F, 0F); prevLooking.setAngles((seatInfo.minYaw + seatInfo.maxYaw) / 2, 0F, 0F); playerPosX = prevPlayerPosX = posX = driveable.posX; playerPosY = prevPlayerPosY = posY = driveable.posY; playerPosZ = prevPlayerPosZ = posZ = driveable.posZ; setPosition(posX, posY, posZ); } //Update gun delay ticker if(gunDelay > 0) gunDelay--; //Update sound delay ticker if(soundDelay > 0) soundDelay--; if(yawSoundDelay > 0) yawSoundDelay--; if(pitchSoundDelay > 0) pitchSoundDelay--; //updatePosition(); if (playYawSound == true && yawSoundDelay == 0 && seatInfo.traverseSounds == true) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, 50, dimension, seatInfo.yawSound, false); yawSoundDelay = seatInfo.yawSoundLength; } if (playPitchSound == true && pitchSoundDelay == 0 && seatInfo.traverseSounds == true) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, 50, dimension, seatInfo.pitchSound, false); pitchSoundDelay = seatInfo.pitchSoundLength; } boolean isThePlayer = riddenByEntity instanceof EntityPlayer && FlansMod.proxy.isThePlayer((EntityPlayer)riddenByEntity); //Reset traverse sounds if player exits the vehicle if(isThePlayer) { playYawSound = false; playPitchSound = false; yawSoundDelay = 0; pitchSoundDelay = 0; } //If on the client if(worldObj.isRemote) { if(driver && isThePlayer && FlansMod.proxy.mouseControlEnabled() && driveable.hasMouseControlMode()) { looking = new RotatedAxes(); playerLooking = new RotatedAxes(); } } if(riddenByEntity instanceof EntityPlayer && shooting) pressKey(9, (EntityPlayer)riddenByEntity); minigunSpeed *= 0.95F; minigunAngle += minigunSpeed; //prevLooking = looking.clone(); } /** Set the position to be that of the driveable plus the local position, rotated */ public void updatePosition() { //If we haven't found our driveable, give up if(worldObj.isRemote && !foundDriveable) return; prevPlayerPosX = playerPosX; prevPlayerPosY = playerPosY; prevPlayerPosZ = playerPosZ; prevPlayerYaw = playerYaw; prevPlayerPitch = playerPitch; prevPlayerRoll = playerRoll; //Get the position of this seat on the driveable axes Vector3f localPosition = new Vector3f(seatInfo.x / 16F, seatInfo.y / 16F, seatInfo.z / 16F); //Rotate the offset vector by the turret yaw if(driveable != null && driveable.seats != null && driveable.seats[0] != null && driveable.seats[0].looking != null) { RotatedAxes yawOnlyLooking = new RotatedAxes(driveable.seats[0].looking.getYaw(), 0F, 0F); Vector3f rotatedOffset = yawOnlyLooking.findLocalVectorGlobally(seatInfo.rotatedOffset); Vector3f.add(localPosition, new Vector3f(rotatedOffset.x, 0F, rotatedOffset.z), localPosition); } //If this seat is connected to the turret, then its position vector on the driveable axes needs an extra rotation in it //if(driveable.rotateWithTurret(seatInfo) && driveable.seats[0] != null) //localPosition = driveable.seats[0].looking.findLocalVectorGlobally(localPosition); //Get the position of this seat globally, but positionally relative to the driveable Vector3f relativePosition = driveable.axes.findLocalVectorGlobally(localPosition); //Set the absol setPosition(driveable.posX + relativePosition.x, driveable.posY + relativePosition.y, driveable.posZ + relativePosition.z); if(riddenByEntity != null) { DriveableType type = driveable.getDriveableType(); Vec3 yOffset = driveable.axes.findLocalVectorGlobally(new Vector3f(0, riddenByEntity.getEyeHeight() * 3 / 4, 0)).toVec3().subtract(0, riddenByEntity.getEyeHeight(), 0); //driveable.rotate(0, riddenByEntity.getYOffset(), 0).toVec3(); playerPosX = posX + yOffset.xCoord; playerPosY = posY + yOffset.yCoord; playerPosZ = posZ + yOffset.zCoord; riddenByEntity.lastTickPosX = riddenByEntity.prevPosX = prevPlayerPosX; riddenByEntity.lastTickPosY = riddenByEntity.prevPosY = prevPlayerPosY; riddenByEntity.lastTickPosZ = riddenByEntity.prevPosZ = prevPlayerPosZ; riddenByEntity.setPosition(playerPosX, playerPosY, playerPosZ); //Calculate the local look axes globally RotatedAxes globalLookAxes = driveable.axes.findLocalAxesGlobally(playerLooking); //Set the player's rotation based on this playerYaw = -90F + globalLookAxes.getYaw(); playerPitch = globalLookAxes.getPitch(); double dYaw = playerYaw - prevPlayerYaw; if(dYaw > 180) prevPlayerYaw += 360F; if(dYaw < -180) prevPlayerYaw -= 360F; if(riddenByEntity instanceof EntityPlayer) { riddenByEntity.prevRotationYaw = prevPlayerYaw; riddenByEntity.prevRotationPitch = prevPlayerPitch; riddenByEntity.rotationYaw = playerYaw; riddenByEntity.rotationPitch = playerPitch; } //If the entity is a player, roll its view accordingly if(worldObj.isRemote) { playerRoll = -globalLookAxes.getRoll(); } } } @Override @SideOnly(Side.CLIENT) public EntityLivingBase getCamera() { return driveable.getCamera(); } @Override public boolean canBeCollidedWith() { return !isDead; } @Override protected void entityInit() { } @Override protected void readEntityFromNBT(NBTTagCompound tags) { //Do not read. Spawn with driveable } @Override protected void writeEntityToNBT(NBTTagCompound tags) { //Do not write. Spawn with driveable } @Override public boolean writeToNBTOptional(NBTTagCompound tags) { return false; } @Override public boolean writeMountToNBT(NBTTagCompound tags) { return false; } @Override public void onMouseMoved(int deltaX, int deltaY) { if(!foundDriveable) return; prevLooking = looking.clone(); prevPlayerLooking = playerLooking.clone(); //Driver seat should pass input to driveable if(driver) { driveable.onMouseMoved(deltaX, deltaY); } //Other seats should look around, but also the driver seat if mouse control mode is disabled if(!driver || !FlansModClient.controlModeMouse || !driveable.hasMouseControlMode()) { float lookSpeed = 4F; //Angle stuff for the player //Calculate the new pitch and consider pitch limiters float newPlayerPitch = playerLooking.getPitch() - deltaY / lookSpeed * Minecraft.getMinecraft().gameSettings.mouseSensitivity; if(newPlayerPitch > -seatInfo.minPitch) newPlayerPitch = -seatInfo.minPitch; if(newPlayerPitch < -seatInfo.maxPitch) newPlayerPitch = -seatInfo.maxPitch; //Calculate new yaw and consider yaw limiters float newPlayerYaw = playerLooking.getYaw() + deltaX / lookSpeed * Minecraft.getMinecraft().gameSettings.mouseSensitivity; //Since the yaw limiters go from -360 to 360, we need to find a pair of yaw values and check them both float otherNewPlayerYaw = newPlayerYaw - 360F; if(newPlayerYaw < 0) otherNewPlayerYaw = newPlayerYaw + 360F; if((newPlayerYaw >= seatInfo.minYaw && newPlayerYaw <= seatInfo.maxYaw) || (otherNewPlayerYaw >= seatInfo.minYaw && otherNewPlayerYaw <= seatInfo.maxYaw)) { //All is well } else { float newPlayerYawDistFromRange = Math.min(Math.abs(newPlayerYaw - seatInfo.minYaw), Math.abs(newPlayerYaw - seatInfo.maxYaw)); float otherPlayerNewYawDistFromRange = Math.min(Math.abs(otherNewPlayerYaw - seatInfo.minYaw), Math.abs(otherNewPlayerYaw - seatInfo.maxYaw)); //If the newYaw is closer to the range than the otherNewYaw, move newYaw into the range if(newPlayerYawDistFromRange <= otherPlayerNewYawDistFromRange) { if(newPlayerYaw > seatInfo.maxYaw) newPlayerYaw = seatInfo.maxYaw; if(newPlayerYaw < seatInfo.minYaw) newPlayerYaw = seatInfo.minYaw; } //Else, the otherNewYaw is closer, so move it in else { if(otherNewPlayerYaw > seatInfo.maxYaw) otherNewPlayerYaw = seatInfo.maxYaw; if(otherNewPlayerYaw < seatInfo.minYaw) otherNewPlayerYaw = seatInfo.minYaw; //Then match up the newYaw with the otherNewYaw if(newPlayerYaw < 0) newPlayerYaw = otherNewPlayerYaw - 360F; else newPlayerYaw = otherNewPlayerYaw + 360F; } } //Now set the new angles playerLooking.setAngles(newPlayerYaw, newPlayerPitch, 0F); //Move the seat accordingly //Consider new Yaw and Yaw limiters float targetX = playerLooking.getYaw(); float yawToMove = (targetX - looking.getYaw()); for(; yawToMove > 180F; yawToMove -= 360F) {} for(; yawToMove <= -180F; yawToMove += 360F) {} float signDeltaX = 0; if(yawToMove > (seatInfo.aimingSpeed.x/2) && seatInfo.legacyAiming == false){ signDeltaX = 1; } else if(yawToMove < -(seatInfo.aimingSpeed.x/2) && seatInfo.legacyAiming == false){ signDeltaX = -1; } else{ signDeltaX = 0; } //Calculate new yaw and consider yaw limiters float newYaw = 0f; if(seatInfo.legacyAiming == true || (signDeltaX == 0 && deltaX == 0)){ newYaw = playerLooking.getYaw(); } else { newYaw = looking.getYaw() + signDeltaX*seatInfo.aimingSpeed.x; } //Since the yaw limiters go from -360 to 360, we need to find a pair of yaw values and check them both float otherNewYaw = newYaw - 360F; if(newYaw < 0) otherNewYaw = newYaw + 360F; if((newYaw >= seatInfo.minYaw && newYaw <= seatInfo.maxYaw) || (otherNewYaw >= seatInfo.minYaw && otherNewYaw <= seatInfo.maxYaw)) { //All is well } else { float newYawDistFromRange = Math.min(Math.abs(newYaw - seatInfo.minYaw), Math.abs(newYaw - seatInfo.maxYaw)); float otherNewYawDistFromRange = Math.min(Math.abs(otherNewYaw - seatInfo.minYaw), Math.abs(otherNewYaw - seatInfo.maxYaw)); //If the newYaw is closer to the range than the otherNewYaw, move newYaw into the range if(newYawDistFromRange <= otherNewYawDistFromRange) { if(newYaw > seatInfo.maxYaw) newYaw = seatInfo.maxYaw; if(newYaw < seatInfo.minYaw) newYaw = seatInfo.minYaw; } //Else, the otherNewYaw is closer, so move it in else { if(otherNewYaw > seatInfo.maxYaw) otherNewYaw = seatInfo.maxYaw; if(otherNewYaw < seatInfo.minYaw) otherNewYaw = seatInfo.minYaw; //Then match up the newYaw with the otherNewYaw if(newYaw < 0) newYaw = otherNewYaw - 360F; else newYaw = otherNewYaw + 360F; } } //Calculate the new pitch and consider pitch limiters float targetY = playerLooking.getPitch(); float pitchToMove = (targetY - looking.getPitch()); for(; pitchToMove > 180F; pitchToMove -= 360F) {} for(; pitchToMove <= -180F; pitchToMove += 360F) {} float signDeltaY = 0; if(pitchToMove > (seatInfo.aimingSpeed.y/2) && seatInfo.legacyAiming == false){ signDeltaY = 1; } else if(pitchToMove < -(seatInfo.aimingSpeed.y/2) && seatInfo.legacyAiming == false){ signDeltaY = -1; } else { signDeltaY = 0; } float newPitch = 0f; //Pitches the gun at the last possible moment in order to reach target pitch at the same time as target yaw. float minYawToMove = 0f; float currentYawToMove = 0f; if(seatInfo.latePitch){ minYawToMove = ((float)Math.sqrt((pitchToMove / seatInfo.aimingSpeed.y)*(pitchToMove / seatInfo.aimingSpeed.y)))*seatInfo.aimingSpeed.x; } else { minYawToMove = 360f; } currentYawToMove = (float)Math.sqrt((yawToMove)*(yawToMove)); if(seatInfo.legacyAiming == true || (signDeltaY == 0 && deltaY == 0)){ newPitch = playerLooking.getPitch(); } else if (seatInfo.yawBeforePitch == false && currentYawToMove < minYawToMove){ newPitch = looking.getPitch() + signDeltaY*seatInfo.aimingSpeed.y; } else if (seatInfo.yawBeforePitch == true && signDeltaX == 0){ newPitch = looking.getPitch() + signDeltaY*seatInfo.aimingSpeed.y; } else if (seatInfo.yawBeforePitch == true && signDeltaX != 0){ newPitch = looking.getPitch(); } else { newPitch = looking.getPitch(); } if(newPitch > -seatInfo.minPitch) newPitch = -seatInfo.minPitch; if(newPitch < -seatInfo.maxPitch) newPitch = -seatInfo.maxPitch; //Now set the new angles looking.setAngles(newYaw, newPitch, 0F); FlansMod.getPacketHandler().sendToServer(new PacketSeatUpdates(this)); if(signDeltaX != 0 && seatInfo.traverseSounds == true){ playYawSound = true; } else { playYawSound = false; } if(signDeltaY != 0 && seatInfo.yawBeforePitch == false && currentYawToMove < minYawToMove){ playPitchSound = true; } else if (signDeltaY != 0 && seatInfo.yawBeforePitch == true && signDeltaX == 0){ playPitchSound = true; } else { playPitchSound = false; } } } @Override public void updateKeyHeldState(int key, boolean held) { if(worldObj.isRemote && foundDriveable) { FlansMod.getPacketHandler().sendToServer(new PacketDriveableKeyHeld(key, held)); } if(driver) { driveable.updateKeyHeldState(key, held); } else if(key == 9) { shooting = held; } } @Override public boolean pressKey(int key, EntityPlayer player) { //Driver seat should pass input to driveable if(driver && (!worldObj.isRemote || foundDriveable)) { return driveable.pressKey(key, player); } if(worldObj.isRemote) { if(foundDriveable) { FlansMod.getPacketHandler().sendToServer(new PacketDriveableKey(key)); if(key == 9) minigunSpeed += 0.1F; } return false; } //Exit key pressed if(key == 6 && riddenByEntity != null) riddenByEntity.mountEntity(null); if(key == 9) //Shoot { //Get the gun from the plane type and the ammo from the data GunType gun = seatInfo.gunType; minigunSpeed += 0.1F; if(gun != null && gun.mode != EnumFireMode.MINIGUN || minigunSpeed > 2F) { if(gunDelay <= 0 && TeamsManager.bulletsEnabled) { ItemStack bulletItemStack = driveable.getDriveableData().ammo[seatInfo.gunnerID]; //Check that neither is null and that the bullet item is actually a bullet if(gun != null && bulletItemStack != null && bulletItemStack.getItem() instanceof ItemShootable) { ShootableType bullet = ((ItemShootable)bulletItemStack.getItem()).type; if(gun.isAmmo(bullet)) { //Gun origin Vector3f gunOrigin = Vector3f.add(driveable.axes.findLocalVectorGlobally(seatInfo.gunOrigin), new Vector3f(driveable.posX, driveable.posY, driveable.posZ), null); //Calculate the look axes globally RotatedAxes globalLookAxes = driveable.axes.findLocalAxesGlobally(looking); Vector3f shootVec = driveable.axes.findLocalVectorGlobally(looking.getXAxis()); //Calculate the origin of the bullets Vector3f yOffset = driveable.axes.findLocalVectorGlobally(new Vector3f(0F, (float)player.getMountedYOffset(), 0F)); //Spawn a new bullet item worldObj.spawnEntityInWorld(((ItemShootable)bulletItemStack.getItem()).getEntity(worldObj, Vector3f.add(yOffset, new Vector3f(gunOrigin.x, gunOrigin.y, gunOrigin.z), null), shootVec, (EntityLivingBase)riddenByEntity, bullet.bulletSpread * gun.bulletSpread, gun.damage, gun.bulletSpeed <= 0.0f ? 5.0f : gun.bulletSpeed, // TODO : Fix nasty hack driveable.getDriveableType())); //Play the shoot sound if(soundDelay <= 0) { PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, gun.shootSound, false); soundDelay = gun.shootSoundLength; } //Get the bullet item damage and increment it int damage = bulletItemStack.getItemDamage(); bulletItemStack.setItemDamage(damage + 1); //If the bullet item is completely damaged (empty) if(damage + 1 == bulletItemStack.getMaxDamage()) { //Set the damage to 0 and consume one ammo item (unless in creative) bulletItemStack.setItemDamage(0); if(!((EntityPlayer)riddenByEntity).capabilities.isCreativeMode) driveable.getDriveableData().decrStackSize(3 + seatID, 1); } //Reset the shoot delay gunDelay = gun.shootDelay; } } } } } return false; } @Override public boolean interactFirst(EntityPlayer entityplayer) //interact : change back when Forge updates { if(isDead) return false; if(worldObj.isRemote) return false; //If they are using a repair tool, don't put them in ItemStack currentItem = entityplayer.getCurrentEquippedItem(); if(currentItem != null && currentItem.getItem() instanceof ItemTool && ((ItemTool)currentItem.getItem()).type.healDriveables) return true; if(currentItem != null && currentItem.getItem() instanceof ItemLead) { if(riddenByEntity != null && riddenByEntity instanceof EntityLiving && !(riddenByEntity instanceof EntityPlayer)) { EntityLiving mob = (EntityLiving)riddenByEntity; riddenByEntity.mountEntity(null); mob.setLeashedToEntity(entityplayer, true); return true; } double checkRange = 10; List nearbyMobs = worldObj.getEntitiesWithinAABB(EntityLiving.class, new AxisAlignedBB(posX - checkRange, posY - checkRange, posZ - checkRange, posX + checkRange, posY + checkRange, posZ + checkRange)); for(Object obj : nearbyMobs) { EntityLiving entity = (EntityLiving)obj; if(entity.getLeashed() && entity.getLeashedToEntity() == entityplayer) { entity.mountEntity(this); looking.setAngles(-entity.rotationYaw, entity.rotationPitch, 0F); entity.clearLeashed(true, !entityplayer.capabilities.isCreativeMode); } } return true; } //Put them in the seat if(riddenByEntity == null && !driveable.getDriveableData().engine.isAIChip) { entityplayer.mountEntity(this); return true; } return false; } @Override public Entity getControllingEntity() { return riddenByEntity; } @Override public boolean isDead() { return isDead; } @Override public void setDead() { super.setDead(); } @Override public void updateRiderPosition() { if(riddenByEntity instanceof EntityPlayer) { riddenByEntity.rotationYaw = playerYaw; riddenByEntity.rotationPitch = playerPitch; riddenByEntity.prevRotationYaw = prevPlayerYaw; riddenByEntity.prevRotationPitch = prevPlayerPitch; } riddenByEntity.lastTickPosX = riddenByEntity.prevPosX = prevPlayerPosX; riddenByEntity.lastTickPosY = riddenByEntity.prevPosY = prevPlayerPosY; riddenByEntity.lastTickPosZ = riddenByEntity.prevPosZ = prevPlayerPosZ; //riddenByEntity.setPosition(playerPosX, playerPosY, playerPosZ); } @Override public ItemStack getPickedResult(MovingObjectPosition target) { if(worldObj.isRemote && !foundDriveable) return null; return driveable.getPickedResult(target); } @Override public float getPlayerRoll() { return playerRoll; } @Override public float getPrevPlayerRoll() { return prevPlayerRoll; } @Override public float getCameraDistance() { return foundDriveable && seatID == 0 ? driveable.getDriveableType().cameraDistance : 5F; } @Override public boolean attackEntityFrom(DamageSource source, float f) { return !(worldObj.isRemote && !foundDriveable) && driveable.attackEntityFrom(source, f); } @Override public void writeSpawnData(ByteBuf data) { data.writeInt(driveableID); data.writeInt(seatInfo.id); } @Override public void readSpawnData(ByteBuf data) { driveableID = data.readInt(); if(worldObj.getEntityByID(driveableID) instanceof EntityDriveable) driveable = (EntityDriveable)worldObj.getEntityByID(driveableID); seatID = data.readInt(); driver = seatID == 0; if(driveable != null) { seatInfo = driveable.getDriveableType().seats[seatID]; looking.setAngles((seatInfo.minYaw + seatInfo.maxYaw) / 2, 0F, 0F); playerPosX = prevPlayerPosX = posX = driveable.posX; playerPosY = prevPlayerPosY = posY = driveable.posY; playerPosZ = prevPlayerPosZ = posZ = driveable.posZ; setPosition(posX, posY, posZ); } } public float getMinigunSpeed() { return minigunSpeed; } }