@Override
  public void updateWeather() {
    super.updateWeather();

    if (!this.worldObj.isRemote) {
      if (this.dataNotLoaded) {
        this.savefile = OrbitSpinSaveData.initWorldData(this.worldObj);
        this.readFromNBT(this.savefile.datacompound);
        if (ConfigManagerCore.enableDebug)
          System.out.println(
              "Loading data from save: " + this.savefile.datacompound.getFloat("omegaSky"));
        this.dataNotLoaded = false;
      }

      if (this.doSpinning) {
        boolean updateNeeded = true;
        if (this.angularVelocityTarget < this.angularVelocityRadians) {
          float newAngle = this.angularVelocityRadians - this.angularVelocityAccel;
          if (newAngle < this.angularVelocityTarget) {
            newAngle = this.angularVelocityTarget;
          }
          this.setSpinRate(newAngle);
          this.thrustersFiring = true;
        } else if (this.angularVelocityTarget > this.angularVelocityRadians) {
          float newAngle = this.angularVelocityRadians + this.angularVelocityAccel;
          if (newAngle > this.angularVelocityTarget) {
            newAngle = this.angularVelocityTarget;
          }
          this.setSpinRate(newAngle);
          this.thrustersFiring = true;
        } else if (this.thrustersFiring) {
          this.thrustersFiring = false;
        } else {
          updateNeeded = false;
        }

        if (updateNeeded) {
          this.writeToNBT(this.savefile.datacompound);
          this.savefile.markDirty();

          List<Object> objList = new ArrayList<Object>();
          objList.add(Float.valueOf(this.angularVelocityRadians));
          objList.add(Boolean.valueOf(this.thrustersFiring));
          GalacticraftCore.packetPipeline.sendToDimension(
              new PacketSimple(EnumSimplePacket.C_UPDATE_STATION_SPIN, objList),
              this.spaceStationDimensionID);
        }

        // Update entity positions if in freefall
        this.loadedEntities.clear();
        this.loadedEntities.addAll(this.worldObj.loadedEntityList);
        for (Entity e : this.loadedEntities) {
          if ((e instanceof EntityItem
                  || e instanceof EntityLivingBase && !(e instanceof EntityPlayer)
                  || e instanceof EntityTNTPrimed
                  || e instanceof EntityFallingBlock)
              && !e.onGround) {
            boolean freefall = true;
            if (e.boundingBox.maxX >= this.ssBoundsMinX
                && e.boundingBox.minX <= this.ssBoundsMaxX
                && e.boundingBox.maxY >= this.ssBoundsMinY
                && e.boundingBox.minY <= this.ssBoundsMaxY
                && e.boundingBox.maxZ >= this.ssBoundsMinZ
                && e.boundingBox.minZ <= this.ssBoundsMaxZ) {
              // Entity is somewhere within the space station boundaries

              // Check if the entity's bounding box is in the same block coordinates as any
              // non-vacuum block (including torches etc)
              // If so, it's assumed the entity has something close enough to catch onto, so is not
              // in freefall
              // Note: breatheable air here means the entity is definitely not in freefall
              int xmx = MathHelper.floor_double(e.boundingBox.maxX + 0.2D);
              int ym = MathHelper.floor_double(e.boundingBox.minY - 0.1D);
              int yy = MathHelper.floor_double(e.boundingBox.maxY + 0.1D);
              int zm = MathHelper.floor_double(e.boundingBox.minZ - 0.2D);
              int zz = MathHelper.floor_double(e.boundingBox.maxZ + 0.2D);
              BLOCKCHECK:
              for (int x = MathHelper.floor_double(e.boundingBox.minX - 0.2D); x <= xmx; x++) {
                for (int y = ym; y <= yy; y++) {
                  for (int z = zm; z <= zz; z++) {
                    if (this.worldObj.blockExists(x, y, z)
                        && this.worldObj.getBlock(x, y, z) != Blocks.air) {
                      freefall = false;
                      break BLOCKCHECK;
                    }
                  }
                }
              }
            }

            if (freefall) {
              // Do the rotation
              if (this.angularVelocityRadians != 0F) {
                float angle;
                final double xx = e.posX - this.spinCentreX;
                final double zz = e.posZ - this.spinCentreZ;
                double arc = Math.sqrt(xx * xx + zz * zz);
                if (xx == 0D) {
                  angle = zz > 0 ? 3.141592536F / 2 : -3.141592536F / 2;
                } else {
                  angle = (float) Math.atan(zz / xx);
                }
                if (xx < 0D) {
                  angle += 3.141592536F;
                }
                angle += this.angularVelocityRadians / 3F;
                arc = arc * this.angularVelocityRadians;
                final double offsetX = -arc * MathHelper.sin(angle);
                final double offsetZ = arc * MathHelper.cos(angle);
                e.posX += offsetX;
                e.posZ += offsetZ;
                e.lastTickPosX += offsetX;
                e.lastTickPosZ += offsetZ;

                // Rotated into an unloaded chunk (probably also drifted out to there): byebye
                if (!this.worldObj.blockExists(
                    MathHelper.floor_double(e.posX), 64, MathHelper.floor_double(e.posZ))) {
                  e.setDead();
                }

                e.boundingBox.offset(offsetX, 0.0D, offsetZ);
                // TODO check for block collisions here - if so move the entity appropriately and
                // apply fall damage
                // Moving the entity = slide along / down
                e.rotationYaw += this.skyAngularVelocity;
                while (e.rotationYaw > 360F) {
                  e.rotationYaw -= 360F;
                }
              }

              // Undo deceleration
              if (e instanceof EntityLivingBase) {
                e.motionX /= 0.91F;
                e.motionZ /= 0.91F;
                if (e instanceof EntityFlying) {
                  e.motionY /= 0.91F;
                } else if (e instanceof EntityFallingBlock) {
                  e.motionY /= 0.9800000190734863D;
                  // e.motionY += 0.03999999910593033D;
                  // e.posY += 0.03999999910593033D;
                  // e.lastTickPosY += 0.03999999910593033D;
                } else {
                  e.motionY /= 0.9800000190734863D;
                }
              } else {
                e.motionX /= 0.9800000190734863D;
                e.motionY /= 0.9800000190734863D;
                e.motionZ /= 0.9800000190734863D;
              }
            }
          }
        }
      }
    }
  }
  public void updateSpinSpeed() {
    if (this.momentOfInertia > 0F) {
      float netTorque = 0F;
      int countThrusters = 0;

      for (BlockVec3 thruster : this.thrustersPlus) {
        float xx = thruster.x - this.massCentreX;
        float zz = thruster.z - this.massCentreZ;
        netTorque += MathHelper.sqrt_float(xx * xx + zz * zz);
        countThrusters++;
      }
      for (BlockVec3 thruster : this.thrustersMinus) {
        float xx = thruster.x - this.massCentreX;
        float zz = thruster.z - this.massCentreZ;
        netTorque -= MathHelper.sqrt_float(xx * xx + zz * zz);
        countThrusters++;
      }

      if (countThrusters == 0) {
        this.angularVelocityAccel = 0.001F;
        this.angularVelocityTarget = 0F;
      } else {
        if (countThrusters > 4) {
          countThrusters = 4;
        }

        float maxRx =
            Math.max(this.ssBoundsMaxX - this.massCentreX, this.massCentreX - this.ssBoundsMinX);
        float maxRz =
            Math.max(this.ssBoundsMaxZ - this.massCentreZ, this.massCentreZ - this.ssBoundsMinZ);
        float maxR = Math.max(maxRx, maxRz);
        this.angularVelocityTarget = MathHelper.sqrt_float(WorldProviderOrbit.GFORCE / maxR) / 2;
        // The divide by 2 is not scientific but is a Minecraft factor as everything happens more
        // quickly
        float spinCap = 0.00125F * countThrusters;

        // TODO: increase this above 20F in release versions so everything happens more slowly
        this.angularVelocityAccel = netTorque / this.momentOfInertia / 20F;
        if (this.angularVelocityAccel < 0) {
          this.angularVelocityAccel = -this.angularVelocityAccel;
          this.angularVelocityTarget = -this.angularVelocityTarget;
          if (this.angularVelocityTarget < -spinCap) {
            this.angularVelocityTarget = -spinCap;
          }
        } else
        // Do not make it spin too fast or players might get dizzy
        // Also make it so players need minimum 4 thrusters for best spin
        if (this.angularVelocityTarget > spinCap) {
          this.angularVelocityTarget = spinCap;
        }

        if (ConfigManagerCore.enableDebug)
          System.out.println(
              "MaxR = "
                  + maxR
                  + " Angular vel = "
                  + this.angularVelocityTarget
                  + " Angular accel = "
                  + this.angularVelocityAccel);
      }
    }

    if (!this.worldObj.isRemote) {
      // Save the updated data for the world
      if (this.savefile == null) {
        this.savefile = OrbitSpinSaveData.initWorldData(this.worldObj);
        this.dataNotLoaded = false;
      } else {
        this.writeToNBT(this.savefile.datacompound);
        this.savefile.markDirty();
      }
    }
  }