private void doAttack(Attack attack) {
    boolean sendToObjectGrid = false;
    boolean sendToDefaultGrid = false;

    Zone zone = PlayerService.getInstance().getZone(playerId);
    if (attack.playerSkill == null) {
      logger.warning("Attack without player skill, ignoring");
      return;
    }

    if (Strings.isNullOrEmpty(attack.attackerCharacterId)) {
      logger.warning("Attack without attackerCharacterId, ignoring");
      return;
    }

    logger.warning(
        "Attack "
            + attack.attackerCharacterId
            + " "
            + attack.targetId
            + " skill "
            + attack.playerSkill.id);

    StatusEffectTarget statusEffectTarget = new StatusEffectTarget();
    VitalsHandler.ensure(playerId, zone.name);

    statusEffectTarget.attack = attack;

    statusEffectTarget.originCharacterId = attack.attackerCharacterId;
    statusEffectTarget.originEntityId = playerId;

    if (attack.playerSkill.category == PlayerSkill.Category.SingleTarget) {
      if (Strings.isNullOrEmpty(attack.targetId)) {
        logger.warning("SingleTarget with no targetId");
        return;
      } else {
        Character character = CharacterService.instance().find(attack.targetId);

        // No character = Object/vehicle/etc..
        if (character == null) {
          if (BuildObjectHandler.exists(attack.targetId)) {
            attack.targetType = Attack.TargetType.BuildObject;
          } else {
            attack.targetType = Attack.TargetType.Object;
          }
          statusEffectTarget.targetEntityId = attack.targetId;
          sendToObjectGrid = true;
        } else {
          attack.targetType = Attack.TargetType.Character;
          statusEffectTarget.targetEntityId = character.playerId;
          sendToDefaultGrid = true;
        }

        ensureTargetVitals(attack.targetType, statusEffectTarget.targetEntityId, zone.name);
      }

    } else if (attack.playerSkill.category == PlayerSkill.Category.Self) {
      attack.targetType = Attack.TargetType.Character;
      statusEffectTarget.targetEntityId = playerId;
      ensureTargetVitals(attack.targetType, statusEffectTarget.targetEntityId, zone.name);
      sendToDefaultGrid = true;

    } else if (attack.playerSkill.category == PlayerSkill.Category.Aoe
        || attack.playerSkill.category == PlayerSkill.Category.AoeDot) {
      if (attack.targetLocation == null) {
        logger.warning("Aoe without targetLocation");
        return;
      }

      statusEffectTarget.location = attack.targetLocation;
      sendToObjectGrid = true;
      sendToDefaultGrid = true;

    } else if (attack.playerSkill.category == PlayerSkill.Category.Pbaoe) {

      Grid grid = GridService.getInstance().getGrid(zone.name, "default");

      TrackData td = grid.get(playerId);
      if (td == null) {
        logger.warning("TrackData not found for " + playerId);
        return;
      }

      statusEffectTarget.location = new GmVector3();
      statusEffectTarget.location.xi = td.x;
      statusEffectTarget.location.yi = td.y;
      statusEffectTarget.location.zi = td.z;

      sendToObjectGrid = true;
      sendToDefaultGrid = true;
    } else {
      logger.warning("Invalid damage type");
      return;
    }

    if (sendToDefaultGrid) {
      StatusEffectManager.tell("default", zone.name, statusEffectTarget.clone(), getSelf());
    }

    if (sendToObjectGrid) {
      StatusEffectManager.tell("build_objects", zone.name, statusEffectTarget.clone(), getSelf());
    }

    sendAttack(attack, zone.name);
  }
  @Override
  public void onGameMessage(GameMessage gameMessage) {

    if (gameMessage.guildAction != null) {
      GuildAction guildAction = gameMessage.guildAction;
      Guild guild = null;
      if (guildAction.action.equals("guilds")) {
        Guilds guilds = new Guilds();
        guilds.guild = Guild.db().findAll();
        gameMessage.guilds = guilds;
        PlayerMessage.tell(gameMessage, playerId);

      } else if (guildAction.action.equals("members")) {
        guild = playerGuild(playerId);
        if (guild != null) {
          Guilds guilds = new Guilds();
          guilds.addGuild(guild);
          gameMessage.guilds = guilds;
          gameMessage.guildMemberList = members(guild.id);
          PlayerMessage.tell(gameMessage, playerId);
        } else {
          logger.warning(playerId + " is not in a guild ");
          return;
        }

      } else if (guildAction.action.equals("create")) {
        if (exists(guildAction.guildId)) {
          return;
        }

        guild = new Guild();
        guild.id = guildAction.guildId;
        guild.name = guildAction.guildName;
        guild.ownerId = playerId;

        save(guild);
        addMember(guild.id, playerId);
        gameMessage.guildAction.response = "success";
        PlayerMessage.tell(gameMessage, playerId);
      } else {

        if (!Strings.isNullOrEmpty(guildAction.guildId)) {
          guild = find(guildAction.guildId);
        }

        if (guildAction.action.equals("accept_invite")) {
          if (invites.containsKey(playerId)) {
            String invite = invites.get(playerId);
            String[] parts = invite.split(Pattern.quote("|"));
            String guildId = parts[0];
            String inviteId = parts[1];
            guild = find(guildId);

            if (invite.equals(guildAction.inviteId)) {
              if (guild == null) {
                logger.warning("Guild not found " + guildId);
                return;
              }

              if (memberOf(guild.id, playerId)) {
                logger.warning(playerId + " is already in guild " + guild.id);
                return;
              }

              addMember(guild.id, playerId);
              gameMessage.guildAction.response = "success";
              PlayerMessage.tell(gameMessage, playerId);
              logger.warning(playerId + " joined guild " + guild.id);
            } else {
              logger.warning(inviteId + " does not match  " + guildAction.inviteId);
            }
          } else {
            logger.warning("Invite not found for " + playerId);
          }

        } else if (guildAction.action.equals("invite")) {
          if (playerId.equals(guild.ownerId)) {
            Random rand = new Random();
            String inviteId = guild.id + "|" + String.valueOf(rand.nextInt(10000) + 10);
            gameMessage.guildAction.inviteId = inviteId;

            // fixme, player id will be null here most likely
            String to = CharacterService.instance().find(guildAction.to).playerId;
            invites.put(to, inviteId);
            if (!Strings.isNullOrEmpty(to)) {
              PlayerMessage.tell(gameMessage, to);
              logger.warning("Invite sent from " + playerId + " to " + guildAction.to);
            } else {
              logger.warning("Player id not found for " + guildAction.to);
            }

          } else {
            gameMessage.guildAction.response = "Not owner";
            PlayerMessage.tell(gameMessage, playerId);
          }

        } else if (guildAction.action.equals("leave")) {
          removeMember(guild.id, playerId);
          if (playerId.equals(guild.ownerId)) {
            destroy(guild);
          }

          gameMessage.guildAction.response = "success";
          PlayerMessage.tell(gameMessage, playerId);

        } else if (guildAction.action.equals("destroy")) {
          if (playerId.equals(guild.ownerId)) {
            destroy(guild);
            gameMessage.guildAction.response = "success";
          } else {
            gameMessage.guildAction.response = "Not owner";
          }
          PlayerMessage.tell(gameMessage, playerId);
        }
      }
    }
  }