content: package com.github.alexthe666.iceandfire.entity.util;
  
  import com.github.alexthe666.citadel.client.model.basic.BasicModelPart;
  import net.minecraft.client.Minecraft;
  import net.minecraft.util.Mth;
  import net.minecraft.world.entity.LivingEntity;
  
  public class ReversedBuffer {
      private int yawTimer;
      private float yawVariation;
      private int pitchTimer;
      private float pitchVariation;
      private float prevYawVariation;
      private float prevPitchVariation;
  
      public void resetRotations() {
          this.yawVariation = 0.0F;
          this.pitchVariation = 0.0F;
          this.prevYawVariation = 0.0F;
          this.prevPitchVariation = 0.0F;
      }
  
      /**
       * Calculates the swing amounts for the given entity (Y axis)
       *
       * @param maxAngle       the furthest this ChainBuffer can swing
       * @param bufferTime     the time it takes to swing this buffer in ticks
       * @param angleDecrement the angle to decrement by for each model piece
       * @param divisor        the amount to divide the swing amount by
       * @param entity         the entity with this ChainBuffer
       */
      public void calculateChainSwingBuffer(float maxAngle, int bufferTime, float angleDecrement, float divisor, LivingEntity entity) {
          this.prevYawVariation = this.yawVariation;
          if (entity.yBodyRot != entity.yBodyRotO && Mth.abs(this.yawVariation) < maxAngle) {
              this.yawVariation += (entity.yBodyRotO - entity.yBodyRot) / divisor;
          }
          if (this.yawVariation > 0.7F * angleDecrement) {
              if (this.yawTimer > bufferTime) {
                  this.yawVariation -= angleDecrement;
                  if (Mth.abs(this.yawVariation) < angleDecrement) {
                      this.yawVariation = 0.0F;
                      this.yawTimer = 0;
                  }
              } else {
                  this.yawTimer++;
              }
          } else if (this.yawVariation < -0.7F * angleDecrement) {
              if (this.yawTimer > bufferTime) {
                  this.yawVariation += angleDecrement;
                  if (Mth.abs(this.yawVariation) < angleDecrement) {
                      this.yawVariation = 0.0F;
                      this.yawTimer = 0;
                  }
              } else {
                  this.yawTimer++;
              }
          }
      }
  
      /**
       * Calculates the wave amounts for the given entity (X axis)
       *
       * @param maxAngle       the furthest this ChainBuffer can wave
       * @param bufferTime     the time it takes to wave this buffer in ticks
       * @param angleDecrement the angle to decrement by for each model piece
       * @param divisor        the amount to divide the wave amount by
       * @param entity         the entity with this ChainBuffer
       */
      public void calculateChainWaveBuffer(float maxAngle, int bufferTime, float angleDecrement, float divisor, LivingEntity entity) {
          this.prevPitchVariation = this.pitchVariation;
          if (entity.getXRot() != entity.xRotO && Mth.abs(this.pitchVariation) < maxAngle) {
              this.pitchVariation += (entity.xRotO - entity.getXRot()) / divisor;
          }
          if (this.pitchVariation > 0.7F * angleDecrement) {
              if (this.pitchTimer > bufferTime) {
                  this.pitchVariation -= angleDecrement;
                  if (Mth.abs(this.pitchVariation) < angleDecrement) {
                      this.pitchVariation = 0.0F;
                      this.pitchTimer = 0;
                  }
              } else {
                  this.pitchTimer++;
              }
          } else if (this.pitchVariation < -0.7F * angleDecrement) {
              if (this.pitchTimer > bufferTime) {
                  this.pitchVariation += angleDecrement;
                  if (Mth.abs(this.pitchVariation) < angleDecrement) {
                      this.pitchVariation = 0.0F;
                      this.pitchTimer = 0;
                  }
              } else {
                  this.pitchTimer++;
              }
          }
      }
  
      /**
       * Calculates the swing amounts for the given entity (Y axis)
       *
       * @param maxAngle       the furthest this ChainBuffer can swing
       * @param bufferTime     the time it takes to swing this buffer in ticks
       * @param angleDecrement the angle to decrement by for each model piece
       * @param entity         the entity with this ChainBuffer
       */
      public void calculateChainSwingBuffer(float maxAngle, int bufferTime, float angleDecrement, LivingEntity entity) {
          this.calculateChainSwingBuffer(maxAngle, bufferTime, angleDecrement, 1.0F, entity);
      }
  
      /**
       * Calculates the wave amounts for the given entity (X axis)
       *
       * @param maxAngle       the furthest this ChainBuffer can wave
       * @param bufferTime     the time it takes to wave this buffer in ticks
       * @param angleDecrement the angle to decrement by for each model piece
       * @param entity         the entity with this ChainBuffer
       */
      public void calculateChainWaveBuffer(float maxAngle, int bufferTime, float angleDecrement, LivingEntity entity) {
          this.calculateChainWaveBuffer(maxAngle, bufferTime, angleDecrement, 1.0F, entity);
      }
  
      /**
       * Applies this buffer on the Y axis to the given array of model boxes.
       *
       * @param boxes the box array
       */
      public void applyChainSwingBuffer(BasicModelPart... boxes) {
          float rotateAmount = 0.01745329251F * Mth.lerp(getPartialTicks(), this.prevYawVariation, this.yawVariation) / boxes.length;
          for (BasicModelPart box : boxes) {
              box.rotateAngleY -= rotateAmount;
          }
      }
  
      /**
       * Applies this buffer on the X axis to the given array of model boxes.
       *
       * @param boxes the box array
       */
      public void applyChainWaveBuffer(BasicModelPart... boxes) {
          float rotateAmount = 0.01745329251F * Mth.lerp(getPartialTicks(), this.prevYawVariation, this.yawVariation) / boxes.length;
          for (BasicModelPart box : boxes) {
              box.rotateAngleX -= rotateAmount;
          }
      }
  
  
      private float getPartialTicks() {
          return Minecraft.getInstance().getFrameTime();
      }
  }