public class ValidatePosition extends L2GameClientPacket {
    private int _x, _y, _z, _heading;
    private int _data; // vehicle id
    @Override
    protected void readImpl() {
        _x = readD();
        _y = readD();
        _z = readD();
        _heading = readD();
        _data = readD();
    }
    @Override
    protected void runImpl() {
        final L2PcInstance activeChar = getClient().getActiveChar();
        if ((activeChar == null) || activeChar.isTeleporting() || activeChar.inObserverMode()) {
            return;
        }
        final int realX = activeChar.getX();
        final int realY = activeChar.getY();
        int realZ = activeChar.getZ();
        if ((_x == 0) && (_y == 0)) {
            if (realX != 0) {
                return;
            }
        }
        int dx, dy, dz;
        double diffSq;
        /*if (activeChar.isInBoat())
         {
         if (Config.COORD_SYNCHRONIZE == 2)
         {
         dx = _x - activeChar.getInVehiclePosition().getX();
         dy = _y - activeChar.getInVehiclePosition().getY();
         // dz = _z - activeChar.getInVehiclePosition().getZ();
         diffSq = ((dx * dx) + (dy * dy));
         if (diffSq > 250000)
         {
         sendPacket(new GetOnVehicle(activeChar.getObjectId(), _data, activeChar.getInVehiclePosition()));
         }
         }
         return;
         }*/
        if (activeChar.isFalling(_z)) {
            return; // disable validations during fall to avoid "jumping"
        }
        dx = _x - realX;
        dy = _y - realY;
        dz = _z - realZ;
        diffSq = ((dx * dx) + (dy * dy));
        // Zoey76: TODO: Implement or cleanup.
        // L2Party party = activeChar.getParty();
        // if ((party != null) && (activeChar.getLastPartyPositionDistance(_x, _y, _z) > 150))
        // {
        // activeChar.setLastPartyPosition(_x, _y, _z);
        // party.broadcastToPartyMembers(activeChar, new PartyMemberPosition(activeChar));
        // }
        if (activeChar.isFlying() || activeChar.isInWater() || activeChar.isInsideZone(L2Zone.FLAG_WATER)) {
            activeChar.getPosition().setXYZ(realX, realY, _z);
            if (diffSq > 90000) {
                activeChar.sendPacket(new ValidateLocation(activeChar));
            }
        } else if (diffSq < 360000) // if too large, messes observation
        {
            if (Config.COORD_SYNCHRONIZE == -1) // Only Z coordinate synched to server,
            // mainly used when no geodata but can be used also with geodata
            {
                activeChar.getPosition().setXYZ(realX, realY, _z);
                return;
            }
            if (Config.COORD_SYNCHRONIZE == 1) // Trusting also client x,y coordinates (should not be used with geodata)
            {
                if (!activeChar.isMoving() || !activeChar.validateMovementHeading(_heading)) // Heading changed on client = possible obstacle
                {
                    // character is not moving, take coordinates from client
                    if (diffSq < 2500) {
                        activeChar.getPosition().setXYZ(realX, realY, _z);
                    } else {
                        activeChar.getPosition().setXYZ(_x, _y, _z);
                    }
                } else {
                    activeChar.getPosition().setXYZ(realX, realY, _z);
                }
                activeChar.setHeading(_heading);
                return;
            }
            // Sync 2 (or other),
            // intended for geodata. Sends a validation packet to client
            // when too far from server calculated true coordinate.
            // Due to geodata/zone errors, some Z axis checks are made. (maybe a temporary solution)
            // Important: this code part must work together with L2Character.updatePosition
            if ((diffSq > 250000) || (Math.abs(dz) > 200)) {
                // if ((_z - activeChar.getClientZ()) < 200 && Math.abs(activeChar.getLastServerPosition().getZ()-realZ) > 70)
                if ((Math.abs(dz) > 200) && (Math.abs(dz) < 1500) && (Math.abs(_z - activeChar.getClientZ()) < 800)) {
                    activeChar.getPosition().setXYZ(realX, realY, _z);
                    realZ = _z;
                } else {
                    if (Config.DEVELOPER) {
                        _log.info(activeChar.getName() + ": Synchronizing position Server --> Client");
                    }
                    activeChar.sendPacket(new ValidateLocation(activeChar));
                }
            }
        }
        activeChar.setClientX(_x);
        activeChar.setClientY(_y);
        activeChar.setClientZ(_z);
        activeChar.setClientHeading(_heading); // No real need to validate heading.
        activeChar.setLastServerPosition(realX, realY, realZ);
        /*L2PcInstance player = getClient().getActiveChar();
         if (player == null || player.isTeleporting()) {
         return;
         }
         player.checkSummon();
         int realX = player.getX();
         int realY = player.getY();
         int realZ = player.getZ();
         if (_x == 0 && _y == 0) {
         if (realX != 0) {
         return;
         }
         }
         double dx = _x - realX;
         double dy = _y - realY;
         double dz = _z - realZ;
         double diffSq = (dx * dx + dy * dy);
         if (player.getParty() != null && player.canSendPartyPos()) {
         player.setLastPartyPosition(_x, _y, _z);
         player.getParty().broadcastToPartyMembers(player, new PartyMemberPosition(player));
         }
         if (player.isFlying() || player.isInWater()) {
         player.setHeading(_heading);
         player.getPosition().setXYZ(realX, realY, _z);
         if (diffSq > 90000) {
         player.sendPacket(new ValidateLocation(player));
         }
         } else if (diffSq < 360000) // if too large, messes observation
         {
         switch (Config.COORD_SYNCHRONIZE) {
         case 1:
         if (!player.isMoving()
         || !player.validateMovementHeading(_heading)) // Heading changed on client = possible obstacle
         {
         // character is not moving, take coordinates from client
         if (diffSq < 2500) // 50*50 - attack won't work fluently if even small differences are corrected
         {
         player.getPosition().setXYZ(realX, realY, _z);
         } else {
         player.getPosition().setXYZ(_x, _y, _z);
         }
         } else {
         player.getPosition().setXYZ(realX, realY, _z);
         }
         player.setHeading(_heading);
         return;
         case 2:
         if (Config.GEODATA > 0 && (diffSq > 250000 || Math.abs(dz) > 200)) {//player.getTemplate().collisionRadius)) {
         //if ((_z - player.getClientZ()) < 200 && Math.abs(player.getLastServerPosition().getZ()-realZ) > 70)
         if (Math.abs(dz) > 200
         && Math.abs(dz) < 1500
         && Math.abs(_z - player.getClientZ()) < 800) {
         player.getPosition().setXYZ(realX, realY, _z);
         realZ = _z;
         } else {
         player.sendPacket(new ValidateLocation(player));
         }
         }
         break;
         default:
         player.getPosition().setXYZ(realX, realY, _z);
         return;
         }
         }
         player.setClientX(_x);
         player.setClientY(_y);
         player.setClientZ(_z);
         player.setClientHeading(_heading); // No real need to validate heading.
         player.setLastServerPosition(realX, realY, realZ);*/
    }
    /*if (Config.COORD_SYNCHRONIZE == -1) // Only Z coordinate synched to server,
     // mainly used when no geodata but can be used also with geodata
     {
     player.getPosition().setXYZ(realX, realY, _z);
     return;
     }
     if (Config.COORD_SYNCHRONIZE == 1) // Trusting also client x,y coordinates (should not be used with geodata)
     {
     if (!player.isMoving()
     || !player.validateMovementHeading(_heading)) // Heading changed on client = possible obstacle
     {
     // character is not moving, take coordinates from client
     if (diffSq < 2500) // 50*50 - attack won't work fluently if even small differences are corrected
     {
     player.getPosition().setXYZ(realX, realY, _z);
     } else {
     player.getPosition().setXYZ(_x, _y, _z);
     }
     } else {
     player.getPosition().setXYZ(realX, realY, _z);
     }
   
     player.setHeading(_heading);
     return;
     }*/
    /*if (Config.GEODATA > 0 && (diffSq > 256 || Math.abs(dz) > 200)) {
     player.sendPacket(new ValidateLocation(player));
     }*/
    // Sync 2 (or other),
    // intended for geodata. Sends a validation packet to client
    // when too far from server calculated true coordinate.
    // Due to geodata/zone errors, some Z axis checks are made. (maybe a temporary solution)
    // Important: this code part must work together with L2Character.updatePosition
            /*if (Config.GEODATA > 0 && (diffSq > 250000 || Math.abs(dz) > 200)) {//player.getTemplate().collisionRadius)) {
     //if ((_z - player.getClientZ()) < 200 && Math.abs(player.getLastServerPosition().getZ()-realZ) > 70)
   
     if (Math.abs(dz) > 200
     && Math.abs(dz) < 1500
     && Math.abs(_z - player.getClientZ()) < 800) {
     player.getPosition().setXYZ(realX, realY, _z);
     System.out.println("##runImpl###1##" + diffSq);
     realZ = _z;
     } else {
     System.out.println("##runImpl###2##" + diffSq);
     player.sendPacket(new ValidateLocation(player));
     }
     }*/
}