Работа над Goddess of Destruction (part 5) - Страница 24 - Форум администраторов игровых серверов
Форум администраторов игровых серверов StormWall - Защита от DDos атак
Регистрация Мнения Справка Пользователи Календарь Все разделы прочитаны
Вернуться   Форум администраторов игровых серверов > MMO > Lineage II

Lineage II
Дискуссии на тему создания, настройки и обслуживания серверов Lineage 2. При поддержке: Премиум услуги по рекламе

Закрытая тема
Опции темы
Непрочитано 08.03.2012, 23:45   #231
Аватар для PROGRAMMATOR
Администратор

По умолчанию Re: Работа над Goddess of Destruction (part 5)

Было же у меня в подписи. (структуры сверять в ручную, ибо они попутаны)
415_Client_Packets_Struct_Opcode.7z
415_Server_Packets_Stuct_Opcode.7z
415_Core_With_GameGuard.7z
415_DisAsm_Packets_Engine.7z
415_Text_Strings_Referenced_In_Engine.7z
PROGRAMMATOR вне форума Отправить сообщение для PROGRAMMATOR с помощью ICQ Отправить сообщение для PROGRAMMATOR с помощью Skype™
Сказали спасибо:
Непрочитано 10.03.2012, 03:08   #232
Изгнанные

По умолчанию Re: Работа над Goddess of Destruction (part 5)

может я нуб и тд, но всёже вот гео енжин для оверов под гео года
PHP код:
package l2p.gameserver.geodata;

import l2p.commons.geometry.Shape;
import l2p.gameserver.Config;
import l2p.gameserver.geodata.GeoOptimizer.BlockLink;
import l2p.gameserver.model.GameObject;
import l2p.gameserver.model.World;
import l2p.gameserver.utils.Location;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: Diamond
 * @CoAuthor: DRiN
 * @Date: 01/03/2009
 */
public class GeoEngine {
    private static final 
Logger _log LoggerFactory.getLogger(GeoEngine.class);

    public static final 
byte EAST 1WEST 2SOUTH 4NORTH 8NSWE_ALL 15NSWE_NONE 0;

    public static final 
byte BLOCKTYPE_FLAT 0;
    public static final 
byte BLOCKTYPE_COMPLEX 1;
    public static final 
byte BLOCKTYPE_MULTILEVEL 2;

    public static final 
int BLOCKS_IN_MAP 256 256;

    public static 
int MAX_LAYERS 1// меньше 1 быть не должно, что бы создавались временные массивы как минимум short[2]

    /**
     * Даный массив содержит эталонную геодату. <BR>
     * Первые 2 [][] (byte[*][*][][]) являются x и y региона.<BR>
     */
    
private static final MappedByteBuffer[][] rawgeo = new MappedByteBuffer[World.WORLD_SIZE_X][World.WORLD_SIZE_Y];

    
/**
     * Даный массив содержит всю геодату на сервере. <BR>
     * Первые 2 [][] (byte[*][*][][]) являются x и y региона.<BR>
     * Третий [] (byte[][][*][]) является блоком геодаты.<BR>
     * Четвертый [] (byte[][][][*]) является контейнером для всех блоков в регионе.<BR>
     */
    
private static final byte[][][][][] geodata = new byte[World.WORLD_SIZE_X][World.WORLD_SIZE_Y][][][];

    public static 
short getType(int xint yint geoIndex) {
        return 
NgetType(World.MAP_MIN_X >> 4World.MAP_MIN_Y >> 4geoIndex);
    }

    public static 
int getHeight(Location locint geoIndex) {
        return 
getHeight(loc.xloc.yloc.zgeoIndex);
    }

    public static 
int getHeight(int xint yint zint geoIndex) {
        return 
NgetHeight(World.MAP_MIN_X >> 4World.MAP_MIN_Y >> 4zgeoIndex);
    }

    public static 
boolean canMoveToCoord(int xint yint zint txint tyint tzint geoIndex) {
        return 
canMove(xyztxtytzfalsegeoIndex) == 0;
    }

    public static 
byte getNSWE(int xint yint zint geoIndex) {
        return 
NgetNSWE(World.MAP_MIN_X >> 4World.MAP_MIN_Y >> 4zgeoIndex);
    }

    public static 
Location moveCheck(int xint yint zint txint tyint geoIndex) {
        return 
MoveCheck(xyztxtyfalsefalsefalsegeoIndex);
    }

    public static 
Location moveCheck(int xint yint zint txint tyboolean returnPrevint geoIndex) {
        return 
MoveCheck(xyztxtyfalsefalsereturnPrevgeoIndex);
    }

    public static 
Location moveCheckWithCollision(int xint yint zint txint tyint geoIndex) {
        return 
MoveCheck(xyztxtytruefalsefalsegeoIndex);
    }

    public static 
Location moveCheckWithCollision(int xint yint zint txint tyboolean returnPrevint geoIndex) {
        return 
MoveCheck(xyztxtytruefalsereturnPrevgeoIndex);
    }

    public static 
Location moveCheckBackward(int xint yint zint txint tyint geoIndex) {
        return 
MoveCheck(xyztxtyfalsetruefalsegeoIndex);
    }

    public static 
Location moveCheckBackward(int xint yint zint txint tyboolean returnPrevint geoIndex) {
        return 
MoveCheck(xyztxtyfalsetruereturnPrevgeoIndex);
    }

    public static 
Location moveCheckBackwardWithCollision(int xint yint zint txint tyint geoIndex) {
        return 
MoveCheck(xyztxtytruetruefalsegeoIndex);
    }

    public static 
Location moveCheckBackwardWithCollision(int xint yint zint txint tyboolean returnPrevint geoIndex) {
        return 
MoveCheck(xyztxtytruetruereturnPrevgeoIndex);
    }

    public static 
Location moveInWaterCheck(int xint yint zint txint tyint tzint waterZint geoIndex) {
        return 
MoveInWaterCheck(World.MAP_MIN_X >> 4World.MAP_MIN_Y >> 4ztx World.MAP_MIN_X >> 4ty World.MAP_MIN_Y >> 4tzwaterZgeoIndex);
    }

    public static 
Location moveCheckForAI(Location loc1Location loc2int geoIndex) {
        return 
MoveCheckForAI(loc1.World.MAP_MIN_X >> 4loc1.World.MAP_MIN_Y >> 4loc1.zloc2.World.MAP_MIN_X >> 4loc2.World.MAP_MIN_Y >> 4geoIndex);
    }

    public static 
Location moveCheckInAir(int xint yint zint txint tyint tzdouble collisionint geoIndex) {
        
int gx World.MAP_MIN_X >> 4;
        
int gy World.MAP_MIN_Y >> 4;
        
int tgx tx World.MAP_MIN_X >> 4;
        
int tgy ty World.MAP_MIN_Y >> 4;

        
int nz NgetHeight(tgxtgytzgeoIndex);

        
// Не даем опуститься ниже, чем пол + 32
        
if (tz <= nz 32)
            
tz nz 32;

        
Location result canSee(gxgyztgxtgytztruegeoIndex);
        if (
result.equals(gxgyz))
            return 
null;

        return 
result.geo2world();
    }

    public static 
boolean canSeeTarget(GameObject actorGameObject targetboolean air) {
        if (
target == null)
            return 
false;
        
// Костыль конечно, но решает кучу проблем с дверьми
        
if (target instanceof GeoCollision || actor.equals(target))
            return 
true;
        return 
canSeeCoord(actortarget.getX(), target.getY(), target.getZ() + (int) target.getColHeight() + 32air);
    }

    public static 
boolean canSeeCoord(GameObject actorint txint tyint tzboolean air) {
        return 
actor != null && canSeeCoord(actor.getX(), actor.getY(), actor.getZ() + (int) actor.getColHeight() + 32txtytzairactor.getGeoIndex());
    }

    public static 
boolean canSeeCoord(int xint yint zint txint tyint tzboolean airint geoIndex) {
        
int mx World.MAP_MIN_X >> 4;
        
int my World.MAP_MIN_Y >> 4;
        
int tmx tx World.MAP_MIN_X >> 4;
        
int tmy ty World.MAP_MIN_Y >> 4;
        return 
canSee(mxmyztmxtmytzairgeoIndex).equals(tmxtmytz) && canSee(tmxtmytzmxmyzairgeoIndex).equals(mxmyz);
    }

    public static 
boolean canMoveWithCollision(int xint yint zint txint tyint tzint geoIndex) {
        return 
canMove(xyztxtytztruegeoIndex) == 0;
    }

    
/**
     * @param NSWE
     * @param x
     * @param y
     * @param tx
     * @param ty
     * @return True if NSWE dont block given direction
     */
    
public static boolean checkNSWE(byte NSWEint xint yint txint ty) {
        if (
NSWE == NSWE_ALL)
            return 
true;
        if (
NSWE == NSWE_NONE)
            return 
false;
        if (
tx x) {
            if ((
NSWE EAST) == 0)
                return 
false;
        } else if (
tx x)
            if ((
NSWE WEST) == 0)
                return 
false;
        if (
ty y) {
            if ((
NSWE SOUTH) == 0)
                return 
false;
        } else if (
ty y)
            if ((
NSWE NORTH) == 0)
                return 
false;
        return 
true;
    }

    public static 
String geoXYZ2Str(int _xint _yint _z) {
        return 
"(" String.valueOf((_x << 4) + World.MAP_MIN_X 8) + " " String.valueOf((_y << 4) + World.MAP_MIN_Y 8) + " " _z ")";
    }

    public static 
String NSWE2Str(byte nswe) {
        
String result "";
        if ((
nswe NORTH) == NORTH)
            
result += "N";
        if ((
nswe SOUTH) == SOUTH)
            
result += "S";
        if ((
nswe WEST) == WEST)
            
result += "W";
        if ((
nswe EAST) == EAST)
            
result += "E";
        return 
result.isEmpty() ? "X" result;
    }

    private static 
boolean NLOS_WATER(int xint yint zint next_xint next_yint next_zint geoIndex) {
        
short[] layers1 = new short[MAX_LAYERS 1];
        
short[] layers2 = new short[MAX_LAYERS 1];
        
NGetLayers(xylayers1geoIndex);
        
NGetLayers(next_xnext_ylayers2geoIndex);

        if (
layers1[0] == || layers2[0] == 0)
            return 
true;

        
short h;

        
// Находим ближайший к целевой клетке слой
        
short z2 Short.MIN_VALUE;
        for (
int i 1<= layers2[0]; i++) {
            
= (short) ((short) (layers2[i] & 0x0fff0) >> 1);
            if (
Math.abs(next_z z2) > Math.abs(next_z h))
                
z2 h;
        }

        
// Луч проходит над преградой
        
if (next_z 32 >= z2)
            return 
true;

        
// Либо перед нами стена, либо над нами потолок. Ищем слой пониже, для уточнения
        
short z3 Short.MIN_VALUE;
        for (
int i 1<= layers2[0]; i++) {
            
= (short) ((short) (layers2[i] & 0x0fff0) >> 1);
            if (
z2 Config.MIN_LAYER_HEIGHT && Math.abs(next_z z3) > Math.abs(next_z h))
                
z3 h;
        }

        
// Ниже нет слоев, значит это стена
        
if (z3 == Short.MIN_VALUE)
            return 
false;

        
// Собираем данные о предыдущей клетке, игнорируя верхние слои
        
short z1 Short.MIN_VALUE;
        
byte NSWE1 NSWE_ALL;
        for (
int i 1<= layers1[0]; i++) {
            
= (short) ((short) (layers1[i] & 0x0fff0) >> 1);
            if (
Config.MIN_LAYER_HEIGHT && Math.abs(z1) > Math.abs(h)) {
                
z1 h;
                
NSWE1 = (byte) (layers1[i] & 0x0F);
            }
        }

        
// Если есть NSWE, то считаем за стену
        
return checkNSWE(NSWE1xynext_xnext_y);
    }

    private static 
int FindNearestLowerLayer(short[] layersint z) {
        
short hnearest_layer_h Short.MIN_VALUE;
        
int nearest_layer Integer.MIN_VALUE;
        for (
int i 1<= layers[0]; i++) {
            
= (short) ((short) (layers[i] & 0x0fff0) >> 1);
            if (
&& nearest_layer_h h) {
                
nearest_layer_h h;
                
nearest_layer layers[i];
            }
        }
        return 
nearest_layer;
    }

    private static 
short CheckNoOneLayerInRangeAndFindNearestLowerLayer(short[] layersint z0int z1) {
        
int z_minz_max;
        if (
z0 z1) {
            
z_min z1;
            
z_max z0;
        } else {
            
z_min z0;
            
z_max z1;
        }
        
short hnearest_layer Short.MIN_VALUEnearest_layer_h Short.MIN_VALUE;
        for (
int i 1<= layers[0]; i++) {
            
= (short) ((short) (layers[i] & 0x0fff0) >> 1);
            if (
z_min <= && <= z_max)
                return 
Short.MIN_VALUE;
            if (
z0 && nearest_layer_h h) {
                
nearest_layer_h h;
                
nearest_layer layers[i];
            }
        }
        return 
nearest_layer;
    }

    public static 
boolean canSeeWallCheck(short layershort nearest_lower_neighborbyte directionNSWEint curr_zboolean air) {
        
short nearest_lower_neighborh = (short) ((short) (nearest_lower_neighbor 0x0fff0) >> 1);
        if (
air)
            return 
nearest_lower_neighborh curr_z;
        
short layerh = (short) ((short) (layer 0x0fff0) >> 1);
        
int zdiff nearest_lower_neighborh layerh;
        return (
layer 0x0F directionNSWE) != || zdiff > -Config.MAX_Z_DIFF && zdiff != 0;
    }

    
/**
     * проверка видимости
     *
     * @return возвращает последнюю точку которую видно (в формате геокоординат)
     *         в результате (Location) h является кодом, если >= 0 то успешно достигли последней точки, если меньше то не последней
     */
    
public static Location canSee(int _xint _yint _zint _txint _tyint _tzboolean airint geoIndex) {
        
int diff_x _tx _xdiff_y _ty _ydiff_z _tz _z;
        
int dx Math.abs(diff_x), dy Math.abs(diff_y);

        
float steps Math.max(dxdy);
        
int curr_x _xcurr_y _ycurr_z _z;
        
short[] curr_layers = new short[MAX_LAYERS 1];
        
NGetLayers(curr_xcurr_ycurr_layersgeoIndex);

        
Location result = new Location(_x_y_z, -1);

        if (
steps == 0) {
            if (
CheckNoOneLayerInRangeAndFindNearestLowerLayer(curr_layerscurr_zcurr_z diff_z) != Short.MIN_VALUE)
                
result.set(_tx_ty_tz1);
            return 
result;
        }

        
float step_x diff_x stepsstep_y diff_y stepsstep_z diff_z steps;
        
float half_step_z step_z 2.0f;
        
float next_x curr_xnext_y curr_ynext_z curr_z;
        
int i_next_xi_next_yi_next_zmiddle_z;
        
short[] tmp_layers = new short[MAX_LAYERS 1];
        
short src_nearest_lower_layerdst_nearest_lower_layertmp_nearest_lower_layer;

        for (
int i 0stepsi++) {
            if (
curr_layers[0] == 0) {
                
result.set(_tx_ty_tz0);
                return 
result// Здесь нет геодаты, разрешаем
            
}

            
next_x += step_x;
            
next_y += step_y;
            
next_z += step_z;
            
i_next_x = (int) (next_x 0.5f);
            
i_next_y = (int) (next_y 0.5f);
            
i_next_z = (int) (next_z 0.5f);
            
middle_z = (int) (curr_z half_step_z);

            if ((
src_nearest_lower_layer CheckNoOneLayerInRangeAndFindNearestLowerLayer(curr_layerscurr_zmiddle_z)) == Short.MIN_VALUE)
                return 
result.setH(-10); // либо есть преграждающая поверхность, либо нет снизу слоя и значит это "пустота", то что за стеной или за колоной

            
NGetLayers(curr_xcurr_ycurr_layersgeoIndex);
            if (
curr_layers[0] == 0) {
                
result.set(_tx_ty_tz0);
                return 
result// Здесь нет геодаты, разрешаем
            
}

            if ((
dst_nearest_lower_layer CheckNoOneLayerInRangeAndFindNearestLowerLayer(curr_layersi_next_zmiddle_z)) == Short.MIN_VALUE)
                return 
result.setH(-11); // либо есть преграда, либо нет снизу слоя и значит это "пустота", то что за стеной или за колоной

            
if (curr_x == i_next_x) {
                
//движемся по вертикали
                
if (!canSeeWallCheck(src_nearest_lower_layerdst_nearest_lower_layeri_next_y curr_y SOUTH NORTHcurr_zair))
                    return 
result.setH(-20);
            } else if (
curr_y == i_next_y) {
                
//движемся по горизонтали
                
if (!canSeeWallCheck(src_nearest_lower_layerdst_nearest_lower_layeri_next_x curr_x EAST WESTcurr_zair))
                    return 
result.setH(-21);
            } else {
                
//движемся по диагонали
                
NGetLayers(curr_xi_next_ytmp_layersgeoIndex);
                if (
tmp_layers[0] == 0) {
                    
result.set(_tx_ty_tz0);
                    return 
result// Здесь нет геодаты, разрешаем
                
}
                if ((
tmp_nearest_lower_layer CheckNoOneLayerInRangeAndFindNearestLowerLayer(tmp_layersi_next_zmiddle_z)) == Short.MIN_VALUE)
                    return 
result.setH(-30); // либо есть преграда, либо нет снизу слоя и значит это "пустота", то что за стеной или за колоной

                
if (!(canSeeWallCheck(src_nearest_lower_layertmp_nearest_lower_layeri_next_y curr_y SOUTH NORTHcurr_zair) && canSeeWallCheck(tmp_nearest_lower_layerdst_nearest_lower_layeri_next_x curr_x EAST WESTcurr_zair))) {
                    
NGetLayers(i_next_xcurr_ytmp_layersgeoIndex);
                    if (
tmp_layers[0] == 0) {
                        
result.set(_tx_ty_tz0);
                        return 
result// Здесь нет геодаты, разрешаем
                    
}
                    if ((
tmp_nearest_lower_layer CheckNoOneLayerInRangeAndFindNearestLowerLayer(tmp_layersi_next_zmiddle_z)) == Short.MIN_VALUE)
                        return 
result.setH(-31); // либо есть преграда, либо нет снизу слоя и значит это "пустота", то что за стеной или за колоной
                    
if (!canSeeWallCheck(src_nearest_lower_layertmp_nearest_lower_layeri_next_x curr_x EAST WESTcurr_zair))
                        return 
result.setH(-32);
                    if (!
canSeeWallCheck(tmp_nearest_lower_layerdst_nearest_lower_layeri_next_x curr_x EAST WESTcurr_zair))
                        return 
result.setH(-33);
                }
            }

            
result.set(curr_xcurr_ycurr_z);
            
curr_x i_next_x;
            
curr_y i_next_y;
            
curr_z i_next_z;
        }

        
result.set(_tx_ty_tz0xFF);
        return 
result;
    }

    private static 
Location MoveInWaterCheck(int xint yint zint txint tyint tzint waterZint geoIndex) {
        
int dx tx x;
        
int dy ty y;
        
int dz tz z;
        
int inc_x sign(dx);
        
int inc_y sign(dy);
        
dx Math.abs(dx);
        
dy Math.abs(dy);
        if (
dx dy == 0)
            return new 
Location(xyz).geo2world();
        
float inc_z_for_x dx == dz dx;
        
float inc_z_for_y dy == dz dy;
        
int prev_x;
        
int prev_y;
        
int prev_z;
        
float next_x x;
        
float next_y y;
        
float next_z z;
        if (
dx >= dy// dy/dx <= 1
        
{
            
int delta_A dy;
            
int d delta_A dx;
            
int delta_B delta_A dx;
            for (
int i 0dxi++) {
                
prev_x x;
                
prev_y y;
                
prev_z z;
                
= (int) next_x;
                
= (int) next_y;
                
= (int) next_z;
                if (
0) {
                    
+= delta_B;
                    
next_x += inc_x;
                    
next_z += inc_z_for_x;
                    
next_y += inc_y;
                    
next_z += inc_z_for_y;
                } else {
                    
+= delta_A;
                    
next_x += inc_x;
                    
next_z += inc_z_for_x;
                }

                if (
next_z >= waterZ || !NLOS_WATER(xyz, (int) next_x, (int) next_y, (int) next_zgeoIndex))
                    return new 
Location(prev_xprev_yprev_z).geo2world();
            }
        } else {
            
int delta_A dx;
            
int d delta_A dy;
            
int delta_B delta_A dy;
            for (
int i 0dyi++) {
                
prev_x x;
                
prev_y y;
                
prev_z z;
                
= (int) next_x;
                
= (int) next_y;
                
= (int) next_z;
                if (
0) {
                    
+= delta_B;
                    
next_x += inc_x;
                    
next_z += inc_z_for_x;
                    
next_y += inc_y;
                    
next_z += inc_z_for_y;
                } else {
                    
+= delta_A;
                    
next_y += inc_y;
                    
next_z += inc_z_for_y;
                }

                if (
next_z >= waterZ || !NLOS_WATER(xyz, (int) next_x, (int) next_y, (int) next_zgeoIndex))
                    return new 
Location(prev_xprev_yprev_z).geo2world();
            }
        }
        return new 
Location((int) next_x, (int) next_y, (int) next_z).geo2world();
    }

    
/**
     * проверка проходимости по прямой
     *
     * @return 0 - проходимо, в ином случае код причины непроходимости (используется при отладке)
     */
    
private static int canMove(int __xint __yint _zint __txint __tyint _tzboolean withCollisionint geoIndex) {
        
int _x __x World.MAP_MIN_X >> 4;
        
int _y __y World.MAP_MIN_Y >> 4;
        
int _tx __tx World.MAP_MIN_X >> 4;
        
int _ty __ty World.MAP_MIN_Y >> 4;
        
int diff_x _tx _xdiff_y _ty _ydiff_z _tz _z;
        
int dx Math.abs(diff_x), dy Math.abs(diff_y), dz Math.abs(diff_z);
        
float steps Math.max(dxdy);
        if (
steps == 0)
            return -
5;

        
int curr_x _xcurr_y _ycurr_z _z;
        
short[] curr_layers = new short[MAX_LAYERS 1];
        
NGetLayers(curr_xcurr_ycurr_layersgeoIndex);
        if (
curr_layers[0] == 0)
            return 
0;

        
float step_x diff_x stepsstep_y diff_y steps;
        
float next_x curr_xnext_y curr_y;
        
int i_next_xi_next_y;

        
short[] next_layers = new short[MAX_LAYERS 1];
        
short[] temp_layers = new short[MAX_LAYERS 1];
        
short[] curr_next_switcher;

        for (
int i 0stepsi++) {
            
next_x += step_x;
            
next_y += step_y;
            
i_next_x = (int) (next_x 0.5f);
            
i_next_y = (int) (next_y 0.5f);
            
NGetLayers(i_next_xi_next_ynext_layersgeoIndex);
            if ((
curr_z NcanMoveNext(curr_xcurr_ycurr_zcurr_layersi_next_xi_next_ynext_layerstemp_layerswithCollisiongeoIndex)) == Integer.MIN_VALUE)
                return 
1;
            
curr_next_switcher curr_layers;
            
curr_layers next_layers;
            
next_layers curr_next_switcher;
            
curr_x i_next_x;
            
curr_y i_next_y;
        }
        
diff_z curr_z _tz;
        
dz Math.abs(diff_z);
        if (
Config.ALLOW_FALL_FROM_WALLS)
            return 
diff_z Config.MAX_Z_DIFF diff_z 10000;
        return 
dz Config.MAX_Z_DIFF dz 1000 0;
    }

    private static 
Location MoveCheck(int __xint __yint _zint __txint __tyboolean withCollisionboolean backwardMoveboolean returnPrevint geoIndex) {
        
int _x __x World.MAP_MIN_X >> 4;
        
int _y __y World.MAP_MIN_Y >> 4;
        
int _tx __tx World.MAP_MIN_X >> 4;
        
int _ty __ty World.MAP_MIN_Y >> 4;

        
int diff_x _tx _xdiff_y _ty _y;
        
int dx Math.abs(diff_x), dy Math.abs(diff_y);
        
float steps Math.max(dxdy);
        if (
steps == 0)
            return new 
Location(__x__y_z);

        
float step_x diff_x stepsstep_y diff_y steps;
        
int curr_x _xcurr_y _ycurr_z _z;
        
float next_x curr_xnext_y curr_y;
        
int i_next_xi_next_yi_next_z curr_z;

        
short[] next_layers = new short[MAX_LAYERS 1];
        
short[] temp_layers = new short[MAX_LAYERS 1];
        
short[] curr_layers = new short[MAX_LAYERS 1];
        
short[] curr_next_switcher;
        
NGetLayers(curr_xcurr_ycurr_layersgeoIndex);
        
int prev_x curr_xprev_y curr_yprev_z curr_z;

        for (
int i 0stepsi++) {
            
next_x += step_x;
            
next_y += step_y;
            
i_next_x = (int) (next_x 0.5f);
            
i_next_y = (int) (next_y 0.5f);
            
NGetLayers(i_next_xi_next_ynext_layersgeoIndex);
            if ((
i_next_z NcanMoveNext(curr_xcurr_ycurr_zcurr_layersi_next_xi_next_ynext_layerstemp_layerswithCollisiongeoIndex)) == Integer.MIN_VALUE)
                break;
            if (
backwardMove && NcanMoveNext(i_next_xi_next_yi_next_znext_layerscurr_xcurr_ycurr_layerstemp_layerswithCollisiongeoIndex) == Integer.MIN_VALUE)
                break;
            
curr_next_switcher curr_layers;
            
curr_layers next_layers;
            
next_layers curr_next_switcher;
            if (
returnPrev) {
                
prev_x curr_x;
                
prev_y curr_y;
                
prev_z curr_z;
            }
            
curr_x i_next_x;
            
curr_y i_next_y;
            
curr_z i_next_z;
        }

        if (
returnPrev) {
            
curr_x prev_x;
            
curr_y prev_y;
            
curr_z prev_z;
        }

        
//if(curr_x == _x && curr_y == _y)
        //    return new Location(__x, __y, _z);

        //log.info("move" + (backwardMove ? " back" : "") + (withCollision ? " +collision" : "") + ": " + curr_x + " " + curr_y + " " + curr_z + " / xyz: " + __x + " " + __y + " " + _z + " / to xy: " + __tx + " " + __ty + " / geo xy: " + _x + " " + _y + " / geo to xy: " + _tx + " " + _ty);
        
return new Location(curr_xcurr_ycurr_z).geo2world();
    }

    
/**
     * Аналогичен CanMove, но возвращает весь пройденный путь. В гео координатах.
     */
    
public static List<LocationMoveList(int __xint __yint _zint __txint __tyint geoIndexboolean onlyFullPath) {
        
int _x __x World.MAP_MIN_X >> 4;
        
int _y __y World.MAP_MIN_Y >> 4;
        
int _tx __tx World.MAP_MIN_X >> 4;
        
int _ty __ty World.MAP_MIN_Y >> 4;

        
int diff_x _tx _xdiff_y _ty _y;
        
int dx Math.abs(diff_x), dy Math.abs(diff_y);
        
double steps Math.max(dxdy);
        if (
steps == 0// Никуда не идем
            
return Collections.emptyList();

        
double step_x diff_x stepsstep_y diff_y steps;
        
int curr_x _xcurr_y _ycurr_z _z;
        
double next_x curr_xnext_y curr_y;
        
int i_next_xi_next_yi_next_z curr_z;

        
short[] next_layers = new short[MAX_LAYERS 1];
        
short[] temp_layers = new short[MAX_LAYERS 1];
        
short[] curr_layers = new short[MAX_LAYERS 1];
        
short[] curr_next_switcher;

        
NGetLayers(curr_xcurr_ycurr_layersgeoIndex);
        if (
curr_layers[0] == 0)
            return 
null;

        List<
Locationresult = new ArrayList<Location>((int) steps 1);

        
result.add(new Location(curr_xcurr_ycurr_z)); // Первая точка

        
steps Math.ceil(steps);
        for (
int i 0< (int) stepsi++) {
            
next_x += step_x;
            
next_y += step_y;
            
i_next_x = (int) (next_x 0.5);
            
i_next_y = (int) (next_y 0.5);

            
NGetLayers(i_next_xi_next_ynext_layersgeoIndex);
            if ((
i_next_z NcanMoveNext(curr_xcurr_ycurr_zcurr_layersi_next_xi_next_ynext_layerstemp_layersfalsegeoIndex)) == Integer.MIN_VALUE)
                if (
onlyFullPath)
                    return 
null;
                else
                    break;

            
curr_next_switcher curr_layers;
            
curr_layers next_layers;
            
next_layers curr_next_switcher;

            
curr_x i_next_x;
            
curr_y i_next_y;
            
curr_z i_next_z;

            
result.add(new Location(curr_xcurr_ycurr_z));
        }

        return 
result;
    }

    
/**
     * Используется только для антипаровоза в AI
     */
    
private static Location MoveCheckForAI(int xint yint zint txint tyint geoIndex) {
        
int dx tx x;
        
int dy ty y;
        
int inc_x sign(dx);
        
int inc_y sign(dy);
        
dx Math.abs(dx);
        
dy Math.abs(dy);
        if (
dx dy || dx == && dy == || dx == && dy == 2)
            return new 
Location(xyz).geo2world();
        
int prev_x x;
        
int prev_y y;
        
int prev_z z;
        
int next_x x;
        
int next_y y;
        
int next_z z;
        if (
dx >= dy// dy/dx <= 1
        
{
            
int delta_A dy;
            
int d delta_A dx;
            
int delta_B delta_A dx;
            for (
int i 0dxi++) {
                
prev_x x;
                
prev_y y;
                
prev_z z;
                
next_x;
                
next_y;
                
next_z;
                if (
0) {
                    
+= delta_B;
                    
next_x += inc_x;
                    
next_y += inc_y;
                } else {
                    
+= delta_A;
                    
next_x += inc_x;
                }
                
next_z NcanMoveNextForAI(xyznext_xnext_ygeoIndex);
                if (
next_z == 0)
                    return new 
Location(prev_xprev_yprev_z).geo2world();
            }
        } else {
            
int delta_A dx;
            
int d delta_A dy;
            
int delta_B delta_A dy;
            for (
int i 0dyi++) {
                
prev_x x;
                
prev_y y;
                
prev_z z;
                
next_x;
                
next_y;
                
next_z;
                if (
0) {
                    
+= delta_B;
                    
next_x += inc_x;
                    
next_y += inc_y;
                } else {
                    
+= delta_A;
                    
next_y += inc_y;
                }
                
next_z NcanMoveNextForAI(xyznext_xnext_ygeoIndex);
                if (
next_z == 0)
                    return new 
Location(prev_xprev_yprev_z).geo2world();
            }
        }
        return new 
Location(next_xnext_ynext_z).geo2world();
    }

    private static 
boolean NcanMoveNextExCheck(int xint yint hint nextxint nextyint hexthshort[] temp_layersint geoIndex) {
        
NGetLayers(xytemp_layersgeoIndex);
        if (
temp_layers[0] == 0)
            return 
true;

        
int temp_layer;
        if ((
temp_layer FindNearestLowerLayer(temp_layersConfig.MIN_LAYER_HEIGHT)) == Integer.MIN_VALUE)
            return 
false;
        
short temp_layer_h = (short) ((short) (temp_layer 0x0fff0) >> 1);
        if (
Math.abs(temp_layer_h hexth) >= Config.MAX_Z_DIFF || Math.abs(temp_layer_h h) >= Config.MAX_Z_DIFF)
            return 
false;
        return 
checkNSWE((byte) (temp_layer 0x0F), xynextxnexty);
    }

    
/**
     * @return возвращает высоту следующего блока, либо Integer.MIN_VALUE если двигатся нельзя
     */
    
public static int NcanMoveNext(int xint yint zshort[] layersint next_xint next_yshort[] next_layersshort[] temp_layersboolean withCollisionint geoIndex) {
        if (
layers[0] == || next_layers[0] == 0)
            return 
z;

        
int layernext_layer;
        if ((
layer FindNearestLowerLayer(layersConfig.MIN_LAYER_HEIGHT)) == Integer.MIN_VALUE)
            return 
Integer.MIN_VALUE;

        
byte layer_nswe = (byte) (layer 0x0F);
        if (!
checkNSWE(layer_nswexynext_xnext_y))
            return 
Integer.MIN_VALUE;

        
short layer_h = (short) ((short) (layer 0x0fff0) >> 1);
        if ((
next_layer FindNearestLowerLayer(next_layerslayer_h Config.MIN_LAYER_HEIGHT)) == Integer.MIN_VALUE)
            return 
Integer.MIN_VALUE;

        
short next_layer_h = (short) ((short) (next_layer 0x0fff0) >> 1);
        
/*if(withCollision && next_layer_h + Config.MAX_Z_DIFF < layer_h)
              return Integer.MIN_VALUE;*/

        // если движение не по диагонали
        
if (== next_x || == next_y) {
            if (
withCollision) {
                
//short[] heightNSWE = temp_layers;
                
if (== next_x) {
                    
NgetHeightAndNSWE(1ylayer_htemp_layersgeoIndex);
                    if (
Math.abs(temp_layers[0] - layer_h) > 15 || !checkNSWE(layer_nswe1yxy) || !checkNSWE((bytetemp_layers[1], 1y1next_y))
                        return 
Integer.MIN_VALUE;

                    
NgetHeightAndNSWE(1ylayer_htemp_layersgeoIndex);
                    if (
Math.abs(temp_layers[0] - layer_h) > 15 || !checkNSWE(layer_nswe1yxy) || !checkNSWE((bytetemp_layers[1], 1y1next_y))
                        return 
Integer.MIN_VALUE;

                    return 
next_layer_h;
                }

                
NgetHeightAndNSWE(x1layer_htemp_layersgeoIndex);
                if (
Math.abs(temp_layers[0] - layer_h) >= Config.MAX_Z_DIFF || !checkNSWE(layer_nswex1xy) || !checkNSWE((bytetemp_layers[1], x1next_x1))
                    return 
Integer.MIN_VALUE;

                
NgetHeightAndNSWE(x1layer_htemp_layersgeoIndex);
                if (
Math.abs(temp_layers[0] - layer_h) >= Config.MAX_Z_DIFF || !checkNSWE(layer_nswex1xy) || !checkNSWE((bytetemp_layers[1], x1next_x1))
                    return 
Integer.MIN_VALUE;
            }

            return 
next_layer_h;
        }

        if (!
NcanMoveNextExCheck(xnext_ylayer_hnext_xnext_ynext_layer_htemp_layersgeoIndex))
            return 
Integer.MIN_VALUE;
        if (!
NcanMoveNextExCheck(next_xylayer_hnext_xnext_ynext_layer_htemp_layersgeoIndex))
            return 
Integer.MIN_VALUE;

        
//FIXME if(withCollision)

        
return next_layer_h;
    }

    
/**
     * Используется только для антипаровоза в AI
     */
    
public static int NcanMoveNextForAI(int xint yint zint next_xint next_yint geoIndex) {
        
short[] layers1 = new short[MAX_LAYERS 1];
        
short[] layers2 = new short[MAX_LAYERS 1];
        
NGetLayers(xylayers1geoIndex);
        
NGetLayers(next_xnext_ylayers2geoIndex);

        if (
layers1[0] == || layers2[0] == 0)
            return 
== z;

        
short h;

        
short z1 Short.MIN_VALUE;
        
byte NSWE1 NSWE_ALL;
        for (
int i 1<= layers1[0]; i++) {
            
= (short) ((short) (layers1[i] & 0x0fff0) >> 1);
            if (
Math.abs(z1) > Math.abs(h)) {
                
z1 h;
                
NSWE1 = (byte) (layers1[i] & 0x0F);
            }
        }

        if (
z1 == Short.MIN_VALUE)
            return 
0;

        
short z2 Short.MIN_VALUE;
        
byte NSWE2 NSWE_ALL;
        for (
int i 1<= layers2[0]; i++) {
            
= (short) ((short) (layers2[i] & 0x0fff0) >> 1);
            if (
Math.abs(z2) > Math.abs(h)) {
                
z2 h;
                
NSWE2 = (byte) (layers2[i] & 0x0F);
            }
        }

        if (
z2 == Short.MIN_VALUE)
            return 
0;

        if (
z1 z2 && z1 z2 Config.MAX_Z_DIFF)
            return 
0;

        if (!
checkNSWE(NSWE1xynext_xnext_y) || !checkNSWE(NSWE2next_xnext_yxy))
            return 
0;

        return 
z2 == z2;
    }

    
/**
     * в нулевую ячейку кладется длина
     *
     * @param geoX
     * @param geoY
     * @param result
     */
    
public static void NGetLayers(int geoXint geoYshort[] resultint geoIndex) {
        
result[0] = 0;
        
byte[] block getGeoBlockFromGeoCoords(geoXgeoYgeoIndex);
        if (
block == null)
            return;

        
int cellXcellY;
        
int index 0;
        
// Read current block type: 0 - flat, 1 - complex, 2 - multilevel
        
byte type block[index];
        
index++;

        switch (
type) {
            case 
BLOCKTYPE_FLAT:
                
short height makeShort(block[index 1], block[index]);
                
height = (short) (height 0x0fff0);
                
result[0]++;
                
result[1] = (short) ((short) (height << 1) | NSWE_ALL);
                return;
            case 
BLOCKTYPE_COMPLEX:
                
cellX getCell(geoX);
                
cellY getCell(geoY);
                
index += (cellX << 3) + cellY << 1;
                
height makeShort(block[index 1], block[index]);
                
result[0]++;
                
result[1] = height;
                return;
            case 
BLOCKTYPE_MULTILEVEL:
                
cellX getCell(geoX);
                
cellY getCell(geoY);
                
int offset = (cellX << 3) + cellY;
                while (
offset 0) {
                    
byte lc block[index];
                    
index += (lc << 1) + 1;
                    
offset--;
                }
                
byte layer_count block[index];
                
index++;
                if (
layer_count <= || layer_count MAX_LAYERS)
                    return;
                
result[0] = layer_count;
                while (
layer_count 0) {
                    
result[layer_count] = makeShort(block[index 1], block[index]);
                    
layer_count--;
                    
index += 2;
                }
                return;
            default:
                
_log.error("GeoEngine: Unknown block type");
                return;
        }
    }

    private static 
short NgetType(int geoXint geoYint geoIndex) {
        
byte[] block getGeoBlockFromGeoCoords(geoXgeoYgeoIndex);

        if (
block == null)
            return 
0;

        return 
block[0];
    }

    public static 
int NgetHeight(int geoXint geoYint zint geoIndex) {
        
byte[] block getGeoBlockFromGeoCoords(geoXgeoYgeoIndex);

        if (
block == null)
            return 
z;

        
int cellXcellYindex 0;

        
// Read current block type: 0 - flat, 1 - complex, 2 - multilevel
        
byte type block[index];
        
index++;

        
short height;
        switch (
type) {
            case 
BLOCKTYPE_FLAT:
                
height makeShort(block[index 1], block[index]);
                return (
short) (height 0x0fff0);
            case 
BLOCKTYPE_COMPLEX:
                
cellX getCell(geoX);
                
cellY getCell(geoY);
                
index += (cellX << 3) + cellY << 1;
                
height makeShort(block[index 1], block[index]);
                return (
short) ((short) (height 0x0fff0) >> 1); // height / 2
            
case BLOCKTYPE_MULTILEVEL:
                
cellX getCell(geoX);
                
cellY getCell(geoY);
                
int offset = (cellX << 3) + cellY;
                while (
offset 0) {
                    
byte lc block[index];
                    
index += (lc << 1) + 1;
                    
offset--;
                }
                
byte layers block[index];
                
index++;
                if (
layers <= || layers MAX_LAYERS)
                    return (
shortz;

                
int z_nearest_lower_limit Config.MIN_LAYER_HEIGHT;
                
int z_nearest_lower Integer.MIN_VALUE;
                
int z_nearest Integer.MIN_VALUE;

                while (
layers 0) {
                    
height = (short) ((short) (makeShort(block[index 1], block[index]) & 0x0fff0) >> 1);
                    if (
height z_nearest_lower_limit)
                        
z_nearest_lower Math.max(z_nearest_lowerheight);
                    else if (
Math.abs(height) < Math.abs(z_nearest))
                        
z_nearest height;
                    
layers--;
                    
index += 2;
                }

                return 
z_nearest_lower != Integer.MIN_VALUE z_nearest_lower z_nearest;
            default:
                
_log.error("GeoEngine: Unknown blockType");
                return 
z;
        }
    }

    
/**
     * @param geoX позиция геодаты
     * @param geoY позиция геодаты
     * @param z    координата без изменений
     * @return NSWE: 0-15
     */
    
public static byte NgetNSWE(int geoXint geoYint zint geoIndex) {
        
byte[] block getGeoBlockFromGeoCoords(geoXgeoYgeoIndex);

        if (
block == null)
            return 
NSWE_ALL;

        
int cellXcellY;
        
int index 0;

        
// Read current block type: 0 - flat, 1 - complex, 2 - multilevel
        
byte type block[index];
        
index++;

        switch (
type) {
            case 
BLOCKTYPE_FLAT:
                return 
NSWE_ALL;
            case 
BLOCKTYPE_COMPLEX:
                
cellX getCell(geoX);
                
cellY getCell(geoY);
                
index += (cellX << 3) + cellY << 1;
                
short height makeShort(block[index 1], block[index]);
                return (
byte) (height 0x0F);
            case 
BLOCKTYPE_MULTILEVEL:
                
cellX getCell(geoX);
                
cellY getCell(geoY);
                
int offset = (cellX << 3) + cellY;
                while (
offset 0) {
                    
byte lc block[index];
                    
index += (lc << 1) + 1;
                    
offset--;
                }
                
byte layers block[index];
                
index++;
                if (
layers <= || layers MAX_LAYERS)
                    return 
NSWE_ALL;

                
short tempz1 Short.MIN_VALUE;
                
short tempz2 Short.MIN_VALUE;
                
int index_nswe1 NSWE_NONE;
                
int index_nswe2 NSWE_NONE;
                
int z_nearest_lower_limit Config.MIN_LAYER_HEIGHT;

                while (
layers 0) {
                    
height = (short) ((short) (makeShort(block[index 1], block[index]) & 0x0fff0) >> 1); // height / 2

                    
if (height z_nearest_lower_limit) {
                        if (
height tempz1) {
                            
tempz1 height;
                            
index_nswe1 index;
                        }
                    } else if (
Math.abs(height) < Math.abs(tempz2)) {
                        
tempz2 height;
                        
index_nswe2 index;
                    }

                    
layers--;
                    
index += 2;
                }

                if (
index_nswe1 0)
                    return (
byte) (makeShort(block[index_nswe1 1], block[index_nswe1]) & 0x0F);
                if (
index_nswe2 0)
                    return (
byte) (makeShort(block[index_nswe2 1], block[index_nswe2]) & 0x0F);

                return 
NSWE_ALL;
            default:
                
_log.error("GeoEngine: Unknown block type.");
                return 
NSWE_ALL;
        }
    }

    public static 
void NgetHeightAndNSWE(int geoXint geoYshort zshort[] resultint geoIndex) {
        
byte[] block getGeoBlockFromGeoCoords(geoXgeoYgeoIndex);

        if (
block == null) {
            
result[0] = z;
            
result[1] = NSWE_ALL;
            return;
        }

        
int cellXcellYindex 0;
        
short heightNSWE NSWE_ALL;

        
// Read current block type: 0 - flat, 1 - complex, 2 - multilevel
        
byte type block[index];
        
index++;

        switch (
type) {
            case 
BLOCKTYPE_FLAT:
                
height makeShort(block[index 1], block[index]);
                
result[0] = (short) (height 0x0fff0);
                
result[1] = NSWE_ALL;
                return;
            case 
BLOCKTYPE_COMPLEX:
                
cellX getCell(geoX);
                
cellY getCell(geoY);
                
index += (cellX << 3) + cellY << 1;
                
height makeShort(block[index 1], block[index]);
                
result[0] = (short) ((short) (height 0x0fff0) >> 1); // height / 2
                
result[1] = (short) (height 0x0F);
                return;
            case 
BLOCKTYPE_MULTILEVEL:
                
cellX getCell(geoX);
                
cellY getCell(geoY);
                
int offset = (cellX << 3) + cellY;
                while (
offset 0) {
                    
byte lc block[index];
                    
index += (lc << 1) + 1;
                    
offset--;
                }
                
byte layers block[index];
                
index++;
                if (
layers <= || layers MAX_LAYERS) {
                    
result[0] = z;
                    
result[1] = NSWE_ALL;
                    return;
                }

                
short tempz1 Short.MIN_VALUE;
                
short tempz2 Short.MIN_VALUE;
                
int index_nswe1 0;
                
int index_nswe2 0;
                
int z_nearest_lower_limit Config.MIN_LAYER_HEIGHT;

                while (
layers 0) {
                    
height = (short) ((short) (makeShort(block[index 1], block[index]) & 0x0fff0) >> 1); // height / 2

                    
if (height z_nearest_lower_limit) {
                        if (
height tempz1) {
                            
tempz1 height;
                            
index_nswe1 index;
                        }
                    } else if (
Math.abs(height) < Math.abs(tempz2)) {
                        
tempz2 height;
                        
index_nswe2 index;
                    }

                    
layers--;
                    
index += 2;
                }

                if (
index_nswe1 0) {
                    
NSWE makeShort(block[index_nswe1 1], block[index_nswe1]);
                    
NSWE = (short) (NSWE 0x0F);
                } else if (
index_nswe2 0) {
                    
NSWE makeShort(block[index_nswe2 1], block[index_nswe2]);
                    
NSWE = (short) (NSWE 0x0F);
                }
                
result[0] = tempz1 Short.MIN_VALUE tempz1 tempz2;
                
result[1] = NSWE;
                return;
            default:
                
_log.error("GeoEngine: Unknown block type.");
                
result[0] = z;
                
result[1] = NSWE_ALL;
                return;
        }
    }

    protected static 
short makeShort(byte b1byte b0) {
        return (
short) (b1 << b0 0xff);
    }

    
/**
     * @param geoPos позиция геодаты
     * @return Block Index: 0-255
     */
    
protected static int getBlock(int geoPos) {
        return (
geoPos >> 3) % 256;
    }

    
/**
     * @param geoPos позиция геодаты
     * @return Cell Index: 0-7
     */
    
protected static int getCell(int geoPos) {
        return 
geoPos 8;
    }

    
/**
     * Создает индекс блока геодаты по заданым координатам блока.
     *
     * @param blockX блок по geoX
     * @param blockY блок по geoY
     * @return индекс блока
     */
    
protected static int getBlockIndex(int blockXint blockY)
    {
        return (
blockX << 8) + blockY;
    }

    private static 
byte sign(int x) {
        if (
>= 0)
            return +
1;
        return -
1;
    }

    
/**
     * Возвращает актуальный блок для текущих геокоординат.<BR>
     * Является заготовкой для возвращения отдельніх блоков с дверьми
     *
     * @param geoX геокоордината
     * @param geoY геокоордината
     * @return текущий блок геодаты, или null если нет геодаты.
     */
    
private static byte[] getGeoBlockFromGeoCoords(int geoXint geoYint geoIndex) {
        if (!
Config.ALLOW_GEODATA)
            return 
null;

        
int ix geoX >> 10;
        
int iy geoY >> 10;

        if(
ix || ix >= World.WORLD_SIZE_X || iy || iy >= World.WORLD_SIZE_Y)
            return 
null;

        
byte[][][] region geodata[ix][iy];

        if(
region == null)
            return 
null;

        
int blockX getBlock(geoX);
        
int blockY getBlock(geoY);

        if(
region.length <= geoIndex)
            
geoIndex 0;

        return 
region[getBlockIndex(blockXblockY)][geoIndex];
    }

    
/**
     * Загрузка геодаты в память
     */
    
public static void load() {
        if (!
Config.ALLOW_GEODATA)
            return;

        
_log.info("GeoEngine: Loading Geodata...");

        
File f = new File(Config.DATAPACK_ROOT"geodata");

        if (!
f.exists() || !f.isDirectory()) {
            
_log.info("GeoEngine: Files missing, loading aborted.");

            return;
        }

        
int counter 0;
        
Pattern p Pattern.compile(Config.GEOFILES_PATTERN);

        for (
File q f.listFiles()) {
            if (
q.isDirectory())
                continue;

            
String fn q.getName();
            
Matcher m p.matcher(fn);
            if (
m.matches()) {
                
fn fn.substring(05); // обрезаем .l2j
                
String[] xy fn.split("_");
                
byte rx Byte.parseByte(xy[0]);
                
byte ry Byte.parseByte(xy[1]);

                
LoadGeodataFile(rxry);
                
LoadGeodata(rxry0);

                
counter++;
            }
        }

        
_log.info("GeoEngine: Loaded " counter " map(s), max layers: " MAX_LAYERS);

        if (
Config.COMPACT_GEO)
            
compact();
    }

    public static 
void DumpGeodata(String dir) {
        new 
File(dir).mkdirs();
        for (
int mapX 0mapX World.WORLD_SIZE_XmapX++)
            for (
int mapY 0mapY World.WORLD_SIZE_YmapY++) {
                if (
geodata[mapX][mapY] == null)
                    continue;
                
int rx mapX Config.GEO_X_FIRST;
                
int ry mapY Config.GEO_Y_FIRST;
                
String fName dir "/" rx "_" ry ".l2j";
                
_log.info("Dumping geo: " fName);
                
DumpGeodataFile(fName, (byterx, (bytery);
            }
    }

    public static 
boolean DumpGeodataFile(int cxint cy) {
        return 
DumpGeodataFileMap((byte) (Math.floor((float) cx / (float) 32768) + 20), (byte) (Math.floor((float) cy / (float) 32768) + 18));
    }

    public static 
boolean DumpGeodataFileMap(byte rxbyte ry) {
        
String name "log/" rx "_" ry ".l2j";
        return 
DumpGeodataFile(namerxry);
    }

    public static 
boolean DumpGeodataFile(String namebyte rxbyte ry) {
        
int ix rx Config.GEO_X_FIRST;
        
int iy ry Config.GEO_Y_FIRST;

        
byte[][] geoblocks geodata[ix][iy][0];
        if (
geoblocks == null)
            return 
false;

        
File f = new File(name);
        if (
f.exists())
            
f.delete();
        
OutputStream os null;
        try {
            
os = new BufferedOutputStream(new FileOutputStream(f));
            for (
byte[] geoblock geoblocks)
                
os.write(geoblock);
        } catch (
IOException e) {
            
_log.error(""e);
            return 
false;
        } 
finally {
            if (
os != null)
                try {
                    
os.close();
                } catch (
Exception e) {

                }
        }

        return 
true;
    }

    
/**
     * Загрузка региона геодаты.
     *
     * @param rx регион x
     * @param ry регион y
     */
    
public static boolean LoadGeodataFile(byte rxbyte ry) {
        
String fname "geodata/" rx "_" ry ".l2j";
        
int ix rx Config.GEO_X_FIRST;
        
int iy ry Config.GEO_Y_FIRST;

        if (
ix || iy || ix > (World.MAP_MAX_X >> 15) + Math.abs(World.MAP_MIN_X >> 15) || iy > (World.MAP_MAX_Y >> 15) + Math.abs(World.MAP_MIN_Y >> 15)) {
            
_log.info("GeoEngine: File " fname " was not loaded!!! ");
            return 
false;
        }

        
_log.info("GeoEngine: Loading: " fname);

        
File geoFile = new File(Config.DATAPACK_ROOTfname);

        try {
            
FileChannel roChannel = new RandomAccessFile(geoFile"r").getChannel();
            
long size roChannel.size();
            
MappedByteBuffer buf roChannel.map(FileChannel.MapMode.READ_ONLY0size);
            
buf.order(ByteOrder.LITTLE_ENDIAN);
            
rawgeo[ix][iy] = buf;

            if (
size BLOCKS_IN_MAP 3)
                throw new 
RuntimeException("Invalid geodata : " fname "!");

            return 
true;
        } catch (
IOException e) {
            
_log.error(""e);
        }

        return 
false;
    }

    public static 
boolean LoadGeodata(int rxint ryint regIndex) {
        
String fname "./geodata/" rx "_" ry ".l2j";
        
int ix rx Config.GEO_X_FIRST;
        
int iy ry Config.GEO_Y_FIRST;

        if(
ix || iy || ix > (World.MAP_MAX_X >> 15) + Math.abs(World.MAP_MIN_X >> 15) || iy > (World.MAP_MAX_Y >> 15) + Math.abs(World.MAP_MIN_Y >> 15))
        {
            
_log.info("Geo Engine: File " fname " was not loaded!!! ");
            return 
false;
        }

        
//log.info("Geo Engine: - Loading: " + fname);

        
File Geo = new File(fname);
        
int sizeindex 0block 0flor 0;
        try
        {
            
byte[] geo;
            
synchronized (geodata)
            {
                
// Create a read-only memory-mapped file
                
FileChannel roChannel = new RandomAccessFile(Geo"r").getChannel();
                
size = (int) roChannel.size();
                
ByteBuffer buffer roChannel.map(FileChannel.MapMode.READ_ONLY0size);
                
roChannel.close();
                
buffer.order(ByteOrder.LITTLE_ENDIAN);
                
geo = new byte[buffer.remaining()];
                
buffer.get(geo0geo.length);
            }
            if(
size >= BLOCKS_IN_MAP 3)
            {
                
byte[][][] blocks = new byte[BLOCKS_IN_MAP][1][]; // 256 * 256 блоков в регионе геодаты

                // Indexing geo files, so we will know where each block starts
                
for(block 0block blocks.lengthblock++)
                {
                    
byte type geo[index];
                    
index++;

                    
byte[] geoBlock;
                    switch(
type)
                    {
                        case 
BLOCKTYPE_FLAT:

                            
// Создаем блок геодаты
                            
geoBlock = new byte[1];

                            
// Читаем нужные даные с геодаты
                            
geoBlock[0] = type;
                            
geoBlock[1] = geo[index];
                            
geoBlock[2] = geo[index 1];

                            
// Увеличиваем индекс
                            
index += 2;

                            
// Добавляем блок геодаты
                            
blocks[block][0] = geoBlock;
                            break;

                        case 
BLOCKTYPE_COMPLEX:

                            
// Создаем блок геодаты
                            
geoBlock = new byte[128 1];

                            
// Читаем даные с геодаты
                            
geoBlock[0] = type;
                            
System.arraycopy(geoindexgeoBlock1128);

                            
// Увеличиваем индекс
                            
index += 128;

                            
// Добавляем блок геодаты
                            
blocks[block][0] = geoBlock;
                            break;

                        case 
BLOCKTYPE_MULTILEVEL:
                            
// Оригинальный индекс
                            
int orgIndex index;

                            
// Считаем длину блока геодаты
                            
for(int b 064b++)
                            {
                                
byte layers geo[index];
                                
MAX_LAYERS Math.max(MAX_LAYERSlayers);
                                
index += (layers << 1) + 1;
                                if(
layers flor)
                                    
flor layers;
                            }

                            
// Получаем длину
                            
int diff index orgIndex;

                            
// Создаем массив геодаты
                            
geoBlock = new byte[diff 1];

                            
// Читаем даные с геодаты
                            
geoBlock[0] = type;
                            
System.arraycopy(geoorgIndexgeoBlock1diff);

                            
// Добавляем блок геодаты
                            
blocks[block][0] = geoBlock;
                            break;
                        default:
                            
_log.info("GeoEngine: invalid block type: " type);
                    }
                }

                
synchronized (geodata)
                {
                    
geodata[ix][iy] = blocks;
                }
                return 
true;
            }
            return 
false;
        }
        catch(
Exception e)
        {
            
e.printStackTrace();
            
_log.warn("Failed to Load GeoFile at block: " block "\n");
            return 
false;
        }
    }

    public static 
int NextGeoIndex(int rxint ryint refId) {
        if (!
Config.ALLOW_GEODATA)
            return 
0;

        
int ix rx Config.GEO_X_FIRST;
        
int iy ry Config.GEO_Y_FIRST;

        
int regIndex = -1;

        
synchronized (geodata) {
            
byte[][][] region geodata[ix][iy];

            
//Ищем свободный блок
            
for (int i 0region.lengthi++) {
                if (
region[i] == null) {
                    
regIndex i;
                    break;
                }
            }

            
//Свободного блока нет, создаем новый
            
if (regIndex == -1) {
                
byte[][][] resizedRegion = new byte[(regIndex region.length) + 1][][];
                for (
int i 0region.lengthi++)
                    
resizedRegion[i] = region[i];
                
geodata[ix][iy] = resizedRegion;
            }

            
LoadGeodata(rxryregIndex);
        }

        return 
0x0f000000 | (ix << 16) | (iy << 8) | regIndex;
    }

    
/**
     * Освободить занятый рефлектом индекс геодаты.
     *
     * @param geoIndex
     */
    
public static void FreeGeoIndex(int geoIndex) {
        if (!
Config.ALLOW_GEODATA)
            return;

        
//Рефлект без геодаты
        
if ((geoIndex 0x0f000000) != 0x0f000000)
            return;

        
int ix = (geoIndex 0x00ff0000) >> 16;
        
int iy = (geoIndex 0x0000ff00) >> 8;
        
int regIndex geoIndex 0x000000ff;

        
synchronized (geodata) {
            
geodata[ix][iy][regIndex] = null;
        }
    }

    
/* NOT USED
     private static void copyBlock(int ix, int iy, int blockIndex)
     {
         byte[][][] region = geodata[ix][iy];

         if(region == null)
         {
             Log.add("door at null region? [" + ix + "][" + iy + "]", "doors");
             return;
         }

         byte[] block = region[blockIndex][0];
         byte blockType = block[0];

         switch(blockType)
         {
             case BLOCKTYPE_FLAT:
                 short height = makeShort(block[2], block[1]);
                 height &= 0x0fff0;
                 height <<= 1;
                 height |= NORTH;
                 height |= SOUTH;
                 height |= WEST;
                 height |= EAST;
                 byte[] newblock = new byte[129];
                 newblock[0] = BLOCKTYPE_COMPLEX;
                 for(int i = 1; i < 129; i += 2)
                 {
                     newblock[i + 1] = (byte) (height >> 8);
                     newblock[i] = (byte) (height & 0x00ff);
                 }
                 region[blockIndex][0] = newblock;
                 break;
             default:
                 if(Config.COMPACT_GEO)
                     region[blockIndex][0] = region[blockIndex][0].clone();
                 break;
         }
     }
     */
    
public static void removeGeoCollision(GeoCollision collisionint geoIndex) {
        
Shape shape collision.getShape();

        
byte[][] around collision.getGeoAround();
        if (
around == null)
            throw new 
RuntimeException("Attempt to remove unitialized collision: " collision);

        
//Размер коллизии в клетках геодаты
        
int minX shape.getXmin() - World.MAP_MIN_X 16 >> 4;
        
int minY shape.getYmin() - World.MAP_MIN_Y 16 >> 4;
        
int minZ shape.getZmin();
        
int maxZ shape.getZmax();

        
short height;
        
byte old_nswe;

        for (
int gX 0gX around.lengthgX++)
            for (
int gY 0gY around[gX].lengthgY++) {
                
int geoX minX gX;
                
int geoY minY gY;

                
byte[] block getGeoBlockFromGeoCoords(geoXgeoYgeoIndex);
                if (
block == null)
                    continue;

                
int cellX getCell(geoX);
                
int cellY getCell(geoY);

                
int index 0;
                
byte blockType block[index];
                
index++;

                switch (
blockType) {
                    case 
BLOCKTYPE_COMPLEX:
                        
index += (cellX << 3) + cellY << 1;

                        
// Получаем высоту клетки
                        
height makeShort(block[index 1], block[index]);
                        
old_nswe = (byte) (height 0x0F);
                        
height &= 0xfff0;
                        
height >>= 1;

                        
// подходящий слой не найден
                        
if (height minZ || height maxZ)
                            break;

                        
// around
                        
height <<= 1;
                        
height &= 0xfff0;
                        
height |= old_nswe;
                        if (
collision.isConcrete())
                            
height |= around[gX][gY];
                        else
                            
height &= ~around[gX][gY];

                        
// Записываем высоту в массив
                        
block[index 1] = (byte) (height >> 8);
                        
block[index] = (byte) (height 0x00ff);
                        break;
                    case 
BLOCKTYPE_MULTILEVEL:
                        
// Последний валидный индекс для двери
                        
int neededIndex = -1;

                        
// Далее следует стандартный механизм получения высоты
                        
int offset = (cellX << 3) + cellY;
                        while (
offset 0) {
                            
byte lc block[index];
                            
index += (lc << 1) + 1;
                            
offset--;
                        }
                        
byte layers block[index];
                        
index++;
                        if (
layers <= || layers MAX_LAYERS)
                            break;
                        
short temph Short.MIN_VALUE;
                        
old_nswe NSWE_ALL;
                        while (
layers 0) {
                            
height makeShort(block[index 1], block[index]);
                            
byte tmp_nswe = (byte) (height 0x0F);
                            
height &= 0xfff0;
                            
height >>= 1;
                            
int z_diff_last Math.abs(minZ temph);
                            
int z_diff_curr Math.abs(maxZ height);
                            if (
z_diff_last z_diff_curr) {
                                
old_nswe tmp_nswe;
                                
temph height;
                                
neededIndex index;
                            }
                            
layers--;
                            
index += 2;
                        }

                        
// подходящий слой не найден
                        
if (temph == Short.MIN_VALUE || (temph minZ || temph maxZ))
                            break;

                        
// around
                        
temph <<= 1;
                        
temph &= 0xfff0;
                        
temph |= old_nswe;
                        if (
collision.isConcrete())
                            
temph |= around[gX][gY];
                        else
                            
temph &= ~around[gX][gY];

                        
// записываем высоту
                        
block[neededIndex 1] = (byte) (temph >> 8);
                        
block[neededIndex] = (byte) (temph 0x00ff);
                        break;
                }
            }
    }

    public static 
void applyGeoCollision(GeoCollision collisionint geoIndex) {
        
Shape shape collision.getShape();
        if (
shape.getXmax() == shape.getYmax() && shape.getXmax() == 0)
            throw new 
RuntimeException("Attempt to add incorrect collision: " collision);

        
boolean isFirstTime false;

        
//Размер коллизии в клетках геодаты
        
int minX shape.getXmin() - World.MAP_MIN_X 16 >> 4;
        
int maxX shape.getXmax() - World.MAP_MIN_X 16 >> 4;
        
int minY shape.getYmin() - World.MAP_MIN_Y 16 >> 4;
        
int maxY shape.getYmax() - World.MAP_MIN_Y 16 >> 4;
        
int minZ shape.getZmin();
        
int maxZ shape.getZmax();

        
byte[][] around collision.getGeoAround();
        if (
around == null) {
            
isFirstTime true;

            
//Сформируем коллизию
            
byte[][] cells = new byte[maxX minX 1][maxY minY 1];
            for (
int gX minXgX <= maxXgX++)
                for (
int gY minYgY <= maxYgY++) {
                    
int x = (gX << 4) + World.MAP_MIN_X;
                    
int y = (gY << 4) + World.MAP_MIN_Y;

                    
loop:
                    for (
int ax xax 16ax++)
                        for (
int ay yay 16ay++)
                            if (
shape.isInside(axay)) {
                                
cells[gX minX][gY minY] = 1;
                                break 
loop;
                            }
                }

            
around = new byte[maxX minX 1][maxY minY 1];
            for (
int gX 0gX cells.lengthgX++)
                for (
int gY 0gY cells[gX].lengthgY++) {
                    if (
cells[gX][gY] == 1) {
                        
around[gX][gY] = NSWE_ALL;

                        
byte _nswe;
                        if (
gY 0)
                            if (
cells[gX][gY 1] == 0) {
                                
_nswe around[gX][gY 1];
                                
_nswe |= SOUTH;
                                
around[gX][gY 1] = _nswe;
                            }
                        if (
gY cells[gX].length)
                            if (
cells[gX][gY 1] == 0) {
                                
_nswe around[gX][gY 1];
                                
_nswe |= NORTH;
                                
around[gX][gY 1] = _nswe;
                            }
                        if (
gX 0)
                            if (
cells[gX 1][gY] == 0) {
                                
_nswe around[gX 1][gY];
                                
_nswe |= EAST;
                                
around[gX 1][gY] = _nswe;
                            }
                        if (
gX cells.length)
                            if (
cells[gX 1][gY] == 0) {
                                
_nswe around[gX 1][gY];
                                
_nswe |= WEST;
                                
around[gX 1][gY] = _nswe;
                            }
                    }
                }

            
collision.setGeoAround(around);
        }

        
short height;
        
byte old_nsweclose_nswe;

        for (
int gX 0gX around.lengthgX++)
            for (
int gY 0gY around[gX].lengthgY++) {
                
int geoX minX gX;
                
int geoY minY gY;

                
// Попытка скопировать блок геодаты, если уже существует, то не скопируется
                //TODO: if(first_time)
                //    copyBlock(ix, iy, blockIndex);

                
byte[] block getGeoBlockFromGeoCoords(geoXgeoYgeoIndex);
                if (
block == null)
                    continue;

                
int cellX getCell(geoX);
                
int cellY getCell(geoY);

                
int index 0;
                
byte blockType block[index];
                
index++;

                switch (
blockType) {
                    case 
BLOCKTYPE_COMPLEX:
                        
index += (cellX << 3) + cellY << 1;

                        
// Получаем высоту клетки
                        
height makeShort(block[index 1], block[index]);
                        
old_nswe = (byte) (height 0x0F);
                        
height &= 0xfff0;
                        
height >>= 1;

                        
// подходящий слой не найден
                        
if (height minZ || height maxZ)
                            break;

                        
close_nswe around[gX][gY];

                        if (
isFirstTime) {
                            if (
collision.isConcrete())
                                
close_nswe &= old_nswe;
                            else
                                
close_nswe &= ~old_nswe;
                            
around[gX][gY] = close_nswe;
                        }

                        
// around
                        
height <<= 1;
                        
height &= 0xfff0;
                        
height |= old_nswe;

                        if (
collision.isConcrete())
                            
height &= ~close_nswe;
                        else
                            
height |= close_nswe;

                        
// Записываем высоту в массив
                        
block[index 1] = (byte) (height >> 8);
                        
block[index] = (byte) (height 0x00ff);
                        break;
                    case 
BLOCKTYPE_MULTILEVEL:
                        
// Последний валидный индекс для двери
                        
int neededIndex = -1;

                        
// Далее следует стандартный механизм получения высоты
                        
int offset = (cellX << 3) + cellY;
                        while (
offset 0) {
                            
byte lc block[index];
                            
index += (lc << 1) + 1;
                            
offset--;
                        }
                        
byte layers block[index];
                        
index++;
                        if (
layers <= || layers MAX_LAYERS)
                            break;
                        
short temph Short.MIN_VALUE;
                        
old_nswe NSWE_ALL;
                        while (
layers 0) {
                            
height makeShort(block[index 1], block[index]);
                            
byte tmp_nswe = (byte) (height 0x0F);
                            
height &= 0xfff0;
                            
height >>= 1;
                            
int z_diff_last Math.abs(minZ temph);
                            
int z_diff_curr Math.abs(maxZ height);
                            if (
z_diff_last z_diff_curr) {
                                
old_nswe tmp_nswe;
                                
temph height;
                                
neededIndex index;
                            }
                            
layers--;
                            
index += 2;
                        }

                        
// подходящий слой не найден
                        
if (temph == Short.MIN_VALUE || (temph minZ || temph maxZ))
                            break;

                        
close_nswe around[gX][gY];

                        if (
isFirstTime) {
                            if (
collision.isConcrete())
                                
close_nswe &= old_nswe;
                            else
                                
close_nswe &= ~old_nswe;
                            
around[gX][gY] = close_nswe;
                        }

                        
// around
                        
temph <<= 1;
                        
temph &= 0xfff0;
                        
temph |= old_nswe;
                        if (
collision.isConcrete())
                            
temph &= ~close_nswe;
                        else
                            
temph |= close_nswe;

                        
// записываем высоту
                        
block[neededIndex 1] = (byte) (temph >> 8);
                        
block[neededIndex] = (byte) (temph 0x00ff);
                        break;
                }
            }
    }

    
/**
     * загружает заранее сгенерированые карты соовпадений в блоках и благодаря им оптимизирует размещение геодаты в памяти
     *
     * @return количество оптимизированых блоков
     */
    
public static void compact() {
        
long total 0optimized 0;
        
BlockLink[] links;
        
byte[][][] link_region;

        for (
int mapX 0mapX World.WORLD_SIZE_XmapX++)
            for (
int mapY 0mapY World.WORLD_SIZE_YmapY++) {
                if (
geodata[mapX][mapY] == null)
                    continue;
                
total += BLOCKS_IN_MAP;
                
links GeoOptimizer.loadBlockMatches("geodata/matches/" + (mapX Config.GEO_X_FIRST) + "_" + (mapY Config.GEO_Y_FIRST) + ".matches");
                if (
links == null)
                    continue;
                for (
int i 0links.lengthi++) {
                    
link_region geodata[links[i].linkMapX][links[i].linkMapY];
                    if (
link_region == null)
                        continue;
                    
link_region[links[i].linkBlockIndex][0] = geodata[mapX][mapY][links[i].blockIndex][0];
                    
optimized++;
                }
            }

        
_log.info(String.format("GeoEngine: - Compacted %d of %d blocks..."optimizedtotal));
    }

    
/**
     * сравнение двух байт-массивов
     *
     * @param a1
     * @param a2
     * @return
     */
    
public static boolean equalsData(byte[] a1byte[] a2) {
        if (
a1.length != a2.length)
            return 
false;
        for (
int i 0a1.lengthi++)
            if (
a1[i] != a2[i])
                return 
false;
        return 
true;
    }

    
/**
     * сравнение двух блоков геодаты
     *
     * @param mapX1
     * @param mapY1
     * @param blockIndex1
     * @param mapX2
     * @param mapY2
     * @param blockIndex2
     * @return
     */
    
public static boolean compareGeoBlocks(int mapX1int mapY1int blockIndex1int mapX2int mapY2int blockIndex2) {
        return 
equalsData(geodata[mapX1][mapY1][blockIndex1][0], geodata[mapX2][mapY2][blockIndex2][0]);
    }

    private static 
void initChecksums() {
        
_log.info("GeoEngine: - Generating Checksums...");
        new 
File(Config.DATAPACK_ROOT"geodata/checksum").mkdirs();
        
ExecutorService executor Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        
GeoOptimizer.checkSums = new int[World.WORLD_SIZE_X][World.WORLD_SIZE_Y][];
        for (
int mapX 0mapX World.WORLD_SIZE_XmapX++)
            for (
int mapY 0mapY World.WORLD_SIZE_YmapY++)
                if (
geodata[mapX][mapY] != null)
                    
executor.execute(new GeoOptimizer.CheckSumLoader(mapXmapYgeodata[mapX][mapY]));
        try {
            
executor.awaitTermination(Long.MAX_VALUETimeUnit.SECONDS);
        } catch (
InterruptedException e) {
            
_log.error(""e);
        }
    }

    private static 
void initBlockMatches(int maxScanRegions) {
        
_log.info("GeoEngine: Generating Block Matches...");
        new 
File(Config.DATAPACK_ROOT"geodata/matches").mkdirs();
        
ExecutorService executor Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        for (
int mapX 0mapX World.WORLD_SIZE_XmapX++)
            for (
int mapY 0mapY World.WORLD_SIZE_YmapY++)
                if (
geodata[mapX][mapY] != null && GeoOptimizer.checkSums != null && GeoOptimizer.checkSums[mapX][mapY] != null)
                    
executor.execute(new GeoOptimizer.GeoBlocksMatchFinder(mapXmapYmaxScanRegions));
        try {
            
executor.awaitTermination(Long.MAX_VALUETimeUnit.SECONDS);
        } catch (
InterruptedException e) {
            
_log.error(""e);
        }
    }

    public static 
void deleteChecksumFiles() {
        for (
int mapX 0mapX World.WORLD_SIZE_XmapX++)
            for (
int mapY 0mapY World.WORLD_SIZE_YmapY++) {
                if (
geodata[mapX][mapY] == null)
                    continue;
                new 
File(Config.DATAPACK_ROOT"geodata/checksum/" + (mapX Config.GEO_X_FIRST) + "_" + (mapY Config.GEO_Y_FIRST) + ".crc").delete();
            }
    }

    public static 
void genBlockMatches(int maxScanRegions) {
        
initChecksums();
        
initBlockMatches(maxScanRegions);
    }

    public static 
void unload() {
        for (
int mapX 0mapX World.WORLD_SIZE_XmapX++)
            for (
int mapY 0mapY World.WORLD_SIZE_YmapY++)
                
geodata[mapX][mapY] = null;
    }

Darvin вне форума Отправить сообщение для Darvin с помощью ICQ Отправить сообщение для Darvin с помощью Skype™
Непрочитано 10.03.2012, 03:34   #233
Аватар для ANZO
Разработчик BDO Emu

По умолчанию Re: Работа над Goddess of Destruction (part 5)

Мде, все что поменять надо было это

Цитата:
World.MAP_MIN_Y
World.MAP_MAX_Y
World.MAP_MIN_X
World.MAP_MAX_X
ANZO вне форума Отправить сообщение для ANZO с помощью ICQ Отправить сообщение для ANZO с помощью Skype™
Сказали спасибо:
Непрочитано 10.03.2012, 12:22   #234
Изгнанные

По умолчанию Re: Работа над Goddess of Destruction (part 5)

нет там немного по другому я сделал. мне кажеться так более лучше получилось
Darvin вне форума Отправить сообщение для Darvin с помощью ICQ Отправить сообщение для Darvin с помощью Skype™
Непрочитано 10.03.2012, 12:50   #235
Аватар для darkevil

По умолчанию Re: Работа над Goddess of Destruction (part 5)

Лезть в двиг геодаты не понимая как вся эта ахинея работает все равно что лезть в двигатель самолета ни разу не видев его в глаза, 1н косяк и сотни пассажиров в лепешку.
__________________
darkevil вне форума Отправить сообщение для darkevil с помощью ICQ Отправить сообщение для darkevil с помощью Skype™
Сказали спасибо:
Непрочитано 10.03.2012, 19:16   #236
Аватар для apocalipce
Пользователь

По умолчанию Re: Работа над Goddess of Destruction (part 5)

Кто-нибудь есть система подъема и magmeld Cruma? У меня проблемы с работы
Lift - elevator ?
apocalipce вне форума
Непрочитано 14.03.2012, 16:58   #237
Аватар для ALF.
Герой

По умолчанию Re: Работа над Goddess of Destruction (part 5)

Ребят скиньте кто то плиз последнюю папку систем с NA-off (с Harmony-update)
ALF. вне форума Отправить сообщение для ALF. с помощью ICQ Отправить сообщение для ALF. с помощью Skype™
Сказали спасибо:
Непрочитано 14.03.2012, 17:01   #238
Аватар для [STIGMATED]
Супергерой

По умолчанию Re: Работа над Goddess of Destruction (part 5)

ALFOS, http://narod.ru/disk/43765225001.5d1...ystem.zip.html

А мне бы с руоффа последний патч.

Последний раз редактировалось [STIGMATED]; 15.03.2012 в 10:55.
[STIGMATED] вне форума Отправить сообщение для [STIGMATED] с помощью Skype™
Сказали спасибо:
Непрочитано 17.03.2012, 23:31   #239
Изгнанные

По умолчанию Re: Работа над Goddess of Destruction (part 5)

ребят, подскажите плиз что за
writeD(0x00);// Unknown GOD
writeD(0x00);// Unknown GOD
writeC(0x00);// Unknown GOD

в пакете UserInfo после writeD(_abnormalEffect2);
Darvin вне форума Отправить сообщение для Darvin с помощью ICQ Отправить сообщение для Darvin с помощью Skype™
Непрочитано 22.03.2012, 06:55   #240
Пользователь

По умолчанию Re: Работа над Goddess of Destruction (part 5)

Поделитесь последним системом с руоффа и подскажите какой сейчас там протокол
PSIFAK вне форума
Закрытая тема

Метки
development, goddess of destruction, l2j, l2p, lineage 2 tauti owned!, tauti, vistall убил 2 часа, атата, гео tauti за картоху, геодата бункера, иди копай, карательный отряд, картоха vs ява, ололо - жесть, технология батарей 0о, у корейцев недержание, шаурмэ фейл


Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 
Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Работа над Goddess of Destruction (part 6) Ashe Lineage II 1304 11.07.2015 20:00
Работа над Goddess of Destruction Вопрос Мараторий Lineage II 29 11.06.2013 18:01
Работа над Goddess of Destruction (part 2) Ozzy Lineage II 411 22.06.2011 15:58
Работа над Goddess of Destruction JaFo Lineage II 409 20.05.2011 01:48
Адаптируем SQL BimBom Работа со скриптами 9 14.10.2009 15:14


© 2007–2020 «Форум администраторов игровых серверов»
Защита сайта от DDoS атак — StormWall
Работает на Булке неизвестной версии с переводом от zCarot
Текущее время: 08:39. Часовой пояс GMT +3.

Вверх