}
}
public static void applyControl(GeoControl control)
{
L2Territory pos = control.getGeoPos();
HashMap<Long, Byte> around = control.getGeoAround();
int refIndex = control.getReflection().getGeoIndex();
boolean first_time = around == null;
// TODO сделать этот самый Init :)
// т.е. скопировать кусок геодаты из реального мира в инстанс, еще до закрытия двери.
if(around == null)
{
around = new HashMap<Long, Byte>();
GArray<Long> around_blocks = new GArray<Long>();
int minX = pos.getXmin() - L2World.MAP_MIN_X >> 4;
int maxX = pos.getXmax() - L2World.MAP_MIN_X >> 4;
int minY = pos.getYmin() - L2World.MAP_MIN_Y >> 4;
int maxY = pos.getYmax() - L2World.MAP_MIN_Y >> 4;
for(int geoX = minX; geoX <= maxX; geoX++)
{
for(int geoY = minY; geoY <= maxY; geoY++)
{
if(check_cell_in_door(geoX, geoY, pos))
{
around_blocks.add(makeLong(geoX, geoY));
}
}
}
for(long geoXY : around_blocks)
{
int geoX = (int) geoXY;
int geoY = (int) (geoXY >> 32);
long aroundN_geoXY = makeLong(geoX, geoY - 1); // close S
long aroundS_geoXY = makeLong(geoX, geoY + 1); // close N
long aroundW_geoXY = makeLong(geoX - 1, geoY); // close E
long aroundE_geoXY = makeLong(geoX + 1, geoY); // close W
around.put(geoXY, NSWE_ALL);
byte _nswe;
if(!around_blocks.contains(aroundN_geoXY))
{
_nswe = around.containsKey(aroundN_geoXY) ? around.remove(aroundN_geoXY) : 0;
_nswe |= SOUTH;
around.put(aroundN_geoXY, _nswe);
}
if(!around_blocks.contains(aroundS_geoXY))
{
_nswe = around.containsKey(aroundS_geoXY) ? around.remove(aroundS_geoXY) : 0;
_nswe |= NORTH;
around.put(aroundS_geoXY, _nswe);
}
if(!around_blocks.contains(aroundW_geoXY))
{
_nswe = around.containsKey(aroundW_geoXY) ? around.remove(aroundW_geoXY) : 0;
_nswe |= EAST;
around.put(aroundW_geoXY, _nswe);
}
if(!around_blocks.contains(aroundE_geoXY))
{
_nswe = around.containsKey(aroundE_geoXY) ? around.remove(aroundE_geoXY) : 0;
_nswe |= WEST;
around.put(aroundE_geoXY, _nswe);
}
}
around_blocks.clear();
control.setGeoAround(around);
}
short height;
byte old_nswe, close_nswe;
synchronized(around)
{
Long[] around_keys = around.keySet().toArray(new Long[around.size()]);
for(long geoXY : around_keys)
{
int geoX = (int) geoXY;
int geoY = (int) (geoXY >> 32);
// Получение мировых координат
int ix = geoX >> 11;
int iy = geoY >> 11;
// Получение индекса блока
int blockX = getBlock(geoX);
int blockY = getBlock(geoY);
int blockIndex = getBlockIndex(blockX, blockY);
// Попытка скопировать блок геодаты, если уже существует, то не скопируется
if(first_time)
{
copyBlock(ix, iy, blockIndex);
}
byte[][][] region = geodata[ix][iy];
if(region == null)
{
Log.add("GeoEngine: Attempt to close door at block with no geodata", "doors");
return;
}
if(region.length <= refIndex)
{
refIndex = 0;
}
byte[] block = region[blockIndex][refIndex];
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(first_time)
{
close_nswe = around.remove(geoXY);
// подходящий слой не найден
if(!check_door_z(pos.getZmin(), pos.getZmax(), height))
{
break;
}
if(control.isGeoCloser())
{
close_nswe &= old_nswe;
}
else
{
close_nswe &= ~old_nswe;
}
around.put(geoXY, close_nswe);
}
else
{
close_nswe = around.get(geoXY);
}
// around
height <<= 1;
height &= 0xfff0;
height |= old_nswe;
if(control.isGeoCloser())
{
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 <= 0 || 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(pos.getZmin() - temph);
int z_diff_curr = Math.abs(pos.getZmin() - height);
if(z_diff_last > z_diff_curr)
{
old_nswe = tmp_nswe;
temph = height;
neededIndex = index;
}
layers--;
index += 2;
}
if(first_time)
{
close_nswe = around.remove(geoXY);
// подходящий слой не найден
if(temph == Short.MIN_VALUE || !check_door_z(pos.getZmin(), pos.getZmax(), temph))
{
break;
}
if(control.isGeoCloser())
{