gt:             System.arraycopy(data, 14, squadPacked, 0, squadPacked.length);
context: package com.agorria.ouroboros.simulation.computer;
  
  import com.agorria.ouroboros.core.Constants;
  import com.agorria.ouroboros.core.Utilities;
  import com.agorria.ouroboros.simulation.entity.Container;
  import com.agorria.ouroboros.simulation.entity.Entity;
  import com.agorria.ouroboros.simulation.entity.Factory;
  import com.agorria.ouroboros.simulation.enviroment.Buildable;
  import com.agorria.ouroboros.simulation.enviroment.Node;
  import com.agorria.ouroboros.simulation.enviroment.Player;
  import com.agorria.ouroboros.simulation.enviroment.Squad;
  import com.agorria.ouroboros.simulation.order.Order;
  import com.agorria.ouroboros.simulation.order.OrderMove;
  import com.agorria.ouroboros.simulation.order.OrderSquadTemplate;
  import org.joml.Vector2f;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.function.Function;
  
  /**
   * Created on 12/06/2017.
   * @author Ion Agorria
   *
   * Handles squad manufacturing and commanding
   */
  public class OffensiveTask extends Task {
      private static final long serialVersionUID = Utilities.getClassUID(OffensiveTask.class);
      /** Interval for updating the current threat */
      private static final long THREAT_UPDATE_INTERVAL = 5 * 60 * 1000;
      /** Amount of players to account when making random choice for most threatening players */
      private static final int THREAT_RANDOM = 2;
      /** Current building squad template */
      private SquadTemplate template;
      /** Controlling active squad */
      private Squad squad;
      /** Player comparator */
      private PlayerThreatComparator comparator;
      /** Current threat player */
      private Player threatPlayer;
      /** Current threat update interval */
      private long threatInterval;
  
      public OffensiveTask(ComputerPlayer computerPlayer) {
          super(computerPlayer);
          template = null;
          squad = null;
          comparator = new PlayerThreatComparator(computerPlayer, simulation);
          threatPlayer = null;
          threatInterval = 0;
      }
  
      @Override
      public void dispose() {
          threatPlayer = null;
          if (comparator != null) {
              comparator.dispose();
              comparator = null;
          }
          if (squad != null) {
              squad.dispose();
              squad = null;
          }
          template = null;
          super.dispose();
      }
  
      @Override
      protected void updateBefore(float delta, List<Entity> entities) {
          super.updateBefore(delta, entities);
  
          //Check if template is finished or factory is gone
          if (template != null) {
              if (isTemplateFinished() || computerPlayer.getFactory() == null) {
                  template = null;
                  if (squad != null) {
                      squad.setAssembled();
                  }
              }
          }
  
          //Get thread player
          threatInterval -= Math.round(delta * 1000);
          if (0 >= threatInterval || (threatPlayer != null && !simulation.isPlayerEnemy(player, threatPlayer))) {
              threatInterval = THREAT_UPDATE_INTERVAL;
              threatPlayer = calculateThreatPlayer();
          }
      }
  
      @Override
      protected void updateEntity(float delta, Entity entity) {
          super.updateEntity(delta, entity);
  
          //Add entities that might be marked for template
          Order order = entity.peekOrder();
          if (order instanceof OrderSquadTemplate) {
              if (((OrderSquadTemplate) order).getTemplate() == template) {
                  if (squad == null) {
                      Node start = simulation.getWorld().getNode(entity.getCenter());
                      Node node = simulation.getNearestNode(start, ComputerPlayer.DISTANCE_BASE_MAX, 0, computerPlayer.getRandom());
                      if (node != null) {
                          entity.submitOrder(new OrderMove(node.getX(), node.getY()));
                      }
                      squad = new Squad(entity);
                  } else {
                      squad.addEntity(entity);
                  }
              }
              entity.removeOrder(order.getID());
          }
      }
  
      @Override
      protected void updateAfter(float delta, List<Entity> entities) {
          super.updateAfter(delta, entities);
  
          //Check if there is no template or active squad
          Factory factory = computerPlayer.getFactory();
          if (template == null && squad == null && factory != null) {
              //Get template and request the factory to build it
              Tier tier = computerPlayer.getTier();
              long money = Math.max(0, player.getMoney() - tier.reservedMoney);
              template = SquadTemplate.getSquadTemplate(tier, money, computerPlayer.getRandom());
              if (template != null) {
                  Buildable[] buildables = template.buildables;
                  for (int i = 0; i < buildables.length; i++) {
                      Function<Integer, Order[]> orders = amount -> new Order[] { new OrderSquadTemplate(template) };
                      computerPlayer.requestBuildOrder(factory, buildables[i], template.count[i], orders);
                  }
              }
          }
  
          //There is squad
          if (squad != null) {
              //Squad is complete
              if (squad.isAssembled()) {
                  if (squad.isEmpty()) {
                      //Check if squad is destroyed
                      squad = null;
                  } else {
                      //Set a destination to squad if none
                      if (squad.getTarget() == null) {
                          setSquadTarget(threatPlayer);
                      }
                  }
              }
  
              //Update squad
              if (squad != null) {
                  squad.update();
              }
          }
      }
  
      /** @return true if factory finished queued template */
      private boolean isTemplateFinished() {
          Factory factory = computerPlayer.getFactory();
          if (factory == null) return true;
          if (factory.getFactoryState() != Factory.FactoryState.Idle) return false;
          for (Buildable buildable : template.buildables) {
              if (factory.countBuildOrder(buildable) != 0) {
                  return false;
              }
          }
          return true;
      }
  
      /** Get the most potential threat player */
      private Player calculateThreatPlayer() {
          List<Player> players = new ArrayList<>();
          for (Player other : simulation.getPlayers().values()) {
              //Don't account inactive, self or non enemies
              if (other.isActive() && player != other && simulation.isPlayerEnemy(player, other)) {
                  players.add(other);
              }
          }
          if (players.isEmpty()) return null;
          players.sort(comparator);
          int random = players.size() - 1 - computerPlayer.getRandom().nextInt(THREAT_RANDOM);
          return players.get(Math.max(random, 0));
      }
  
      /** Find position to move according to  */
      private void setSquadTarget(Player enemy) {
          Entity target = null;
  
          //Check if player is not null
          if (enemy != null) {
              //First try around base
              Node node = simulation.getWorld().getNode(computerPlayer.getPlayerBase(enemy));
              LinkedHashSet<Entity> enemyEntities = simulation.getEnemyEntities(node, 0, ComputerPlayer.DISTANCE_BASE_MAX, 1, player);
              Iterator<Entity> iterator = enemyEntities.iterator();
              if (iterator.hasNext()) {
                  target = iterator.next();
              }
  
              //Try any player entity
              if (target == null) {
                  List<Entity> entities = simulation.getEntitiesSelectable(enemy);
                  if (entities != null && !entities.isEmpty()) {
                      target = entities.get(0);
                  }
              }
          }
  
          //Set found target
          squad.setTarget(target);
      }
  
      /** @return squad template */
      public SquadTemplate getSquadTemplate() {
          return template;
      }
  
      /** @return squad */
      public Integer getSquadSize() {
          return squad == null ? null : squad.getSize();
      }
  
      /** @return threat player */
      public Player getThreatPlayer() {
          return threatPlayer;
      }
  
      @Override
      public byte[] pack() {
          byte[] squadPacked = new byte[0];
          if (squad != null) squadPacked = squad.pack();
          byte[] data = new byte[14 + squadPacked.length];
          Utilities.packEnum(data, 0, template);
          if (threatPlayer != null) Utilities.packInt(data, 2, threatPlayer.getID());
          Utilities.packLong(data, 6, threatInterval);
          System.arraycopy(squadPacked, 0, data, 14, squadPacked.length);
          return data;
      }
  
      @Override
      public void unpack(byte[] data) throws IOException {
          template = Utilities.unpackEnum(data, 0, SquadTemplate.values());
          threatPlayer = simulation.getPlayer(Utilities.unpackInt(data, 2));
          threatInterval = Utilities.unpackLong(data, 6);
          byte[] squadPacked = new byte[data.length - 14];
          if (0 < squadPacked.length) {
  