Ровно 20 лет назад, 8 июня 2004 года, в корейской компании NCSoft был скомпилирован файл L2Server.exe - основной компонент игрового сервера новейшей на тот момент ММО игры Lineage II The chaotic chronicle: Chronicle 1 - Harbingers of War. В результате произошедших затем событий, всех подробностей которых мы вероятно никогда не узнаем, этот файл, вместе с сопутствующими компонентами, данными и скриптами стал, так скажем, "достоянием общественности", дав начало эре неофициальных серверов, а также огромной популярности Lineage 2 в СНГ, и не только. В этой, и последующих, статьях мы познакомимся с техническими подробностями и секретами как клиента, так и сервера этой игры, некоторые из которых не были широко известны не только игрокам, но и администраторам серверов.
Дисклеймер: Вся информация предоставляется исключительно в ознакомительных целях и получена из открытых источников. Автор не является, и никогда не являлся, сотрудником компании NCSoft или её партнёров, не заключал с ними никаких соглашений, и не имеет никакого отношения и никакой информации касательно произошедших сливов.
В качестве подопытного будем использовать клиент и сервер C1, как в те времена, а также инструментарий тех времён: отладчик OllyDbg с плагином ODbgScript и дизассемблер IDA. Несмотря на то, что некоторую информацию и инструменты сейчас можно просто нагуглить, пройдем весь путь с нуля, как если бы мы оказались в 2004 году, так что никаких питонов, гидр, и прочего новодела.
Начнём с изучения клиента. В корне клиента лежит файл LineageII.exe - но это лаунчер, нам он не нужен. Можно удалить, чтоб не мешался. Настоящий exe клиента, вместе с dll и конфигами, находится в System и называется l2.bin. Переименуем его в l2.exe и убедимся что клиент нормально запускается.
Настраиваем клиент
Итак, свежеустановленный оригинальный клиент стартует в полноэкранном режиме, а при попытке логина будет пытаться залогиниться на официальный сервер. Нужно разобраться с этими недоразумениями - сделать так, чтоб клиент запускался в окне и логинился на локальный сервер. Клиент основан на модифицированном движке UnrealEngine. В System находится много ini файлов, однако они зашифрованы или запакованы:
Разберёмся с этим. Загрузим клиент под дебаггером, поставим брейкпоинт на CreateFileA и CreateFileW, запустим, проскипаем до места, где будет открываться l2.ini. Выйдя из функции kernel32 попадаем сюда:
Теперь поставим брейкпоинт на ReadFile. После брейка видим такой стек:
Поставим брейкпоинт на доступ к памяти по адресу Buffer + 0x20 (пропускаем заголовок файла), запускаем, срабатывает брейк в core.dll. Выходим из функции, попадаем сюда:
Функция шифрования оказалась в экспорте dll-ки, так что даже не нужно гадать чем зашифровано. Добрые корейцы делают всё для людей :) Выйдя еще на уровень выше, попадаем сюда:
А вот и ключ шифрования. Теперь можно написать дешифровщик и шифровщик, реализацию алгоритма BlowFish возьмём из OpenSSL.
#define La2IniHeaderSize 0x1C
const unsigned char l2_ini_enc_key[] = "[;'.]94-&@%!^+]-31==";
void La2IniDecryptVer212(uint8_t * buf, size_t buf_size) {
BF_KEY key;
BF_set_key(&key, sizeof(l2_ini_enc_key), l2_ini_enc_key);
for (size_t offs = La2IniHeaderSize; offs + BF_BLOCK < buf_size; offs += BF_BLOCK) {
BF_decrypt((unsigned int *)(buf + offs), &key);
}
}
Впрочем, все давно сделано за нас, так что можно воспользоваться тулзой dstuff l2encdec. В расшифрованном l2.ini пропишем:
ServerAddr=127.0.0.1
StartupFullscreen=False
Затем зашифруем обратно и положим файл в System. Теперь клиент стартует в безрамочном окне и логинится на 127.0.0.1:2106. Можно запустить локальный сервер и начать развлекаться. Запуск сервера - это отдельная большая тема, которую я не буду рассматривать в этой статье, отмечу лишь что большинство экспериментов проводилось на самописном минималистичном сервере, на который можно только зайти и соло побегать, так что не удивляйтесь отсутствию мобов и НПЦ.
Находим аргументы командной строки
Теперь посмотрим, принимает ли клиент какие-то аргументы командной строки. Ставим брейкпоинт на GetCommandLineA и GetCommandLineW, запускаем. Срабатывает брейк на GetCommandLineW. Трейсим до выхода из функции, ставим брейк на доступ к памяти по адресу EAX. Брейк срабатывает в функции:
Core.?ParseParam@@YAHPBG0@Z ; ParseParam(ushort const *,ushort const *)
Поскольку она вызывается много раз, воспользуемся скриптом для ODbgScript чтобы сдампить все аргументы:
cycle:
log [esp+4]
log [esp+8]
run
jmp cycle
В результате получаем вот такой список:
Hidden text
STRICT
CONFLICTS
NOGC
NOMMX
NOSSE
SERVER
LAZY
LOG
server
BENCHMARK
320x240
512x384
640x480
800x600
1024x768
1280x960
1280x1024
1600x1200
FirstRun
safe
defaultres
nodeviceid
lanplay
nomusic
NOSOUND
nomusic
windowed
RECORDMOVIE
MEMSTAT
А декомпилировав в IDA функцию ParseParam выясняем, что аргументы должны быть с префиксом '-' или '/':
int __cdecl ParseParam(const unsigned __int16 *a1, wchar_t *Str)
{
...
if ( !v2 )
{
while ( 1 )
{
v3 = appStrfind(v3 + 1, Str);
if ( !v3 )
break;
if ( v3 > a1 )
{
v4 = *(v3 - 1);
if ( v4 == '-' || v4 == '/' )
return 1;
}
}
}
return 0;
}
Настало время воспользоваться полученными знаниями. В первую очередь интересен аргумент LOG, который запускает клиент с открытой игровой консолью:
Из прочих команд:
windowed - по идее должна включать оконный режим но не работает, вероятнее StartupFullscreen из l2.ini приоритетнее;
RECORDMOVIE - таки записывает видео, но в виде кучи скриншотов;
MEMSTAT - пишет в лог статистику при закрытии клиента.
Добываем список консольных команд
Исследуем что же можно сделать через игровую консоль. Подбором обнаруживаем что работают команды exit и quit. Эти строки встречаются в файлах Engine.dll и Core.dll. Грузим Engine.dll и находим где используются эти строки:
.text:104D14A2 lea edx, [ebp+arg_0]
.text:104D14A5 push offset aExit ; "EXIT"
.text:104D14AA push edx
.text:104D14AB call edi ; ParseCommand(ushort const * *,ushort const *) ; ParseCommand(ushort const * *,ushort const *)
.text:104D14AD add esp, 8
.text:104D14B0 cmp eax, ebx
.text:104D14B2 jnz loc_104D17C6
.text:104D14B8 lea eax, [ebp+arg_0]
.text:104D14BB push offset aQuit ; "QUIT"
.text:104D14C0 push eax
.text:104D14C1 call edi ; ParseCommand(ushort const * *,ushort const *) ; ParseCommand(ushort const * *,ushort const *)
ParseCommand - это функция ?ParseCommand@@YAHPAPBGPBG@Z из Core.dll.
Теперь запустим клиент под дебаггером и поставим брейкпоинт на ParseCommand. Введя произвольную команду, обнаруживаем что команды действительно парсятся этой функцией. Теперь можно сдампить список похожим скриптом:
cycle:
log [[esp+4]]
log [esp+8]
run
jmp cycle
В итоге получаем такой список:
Hidden text
OPEN
START
SERVERTRAVEL
DISCONNECT
RECONNECT
EXIT
QUIT
GETCURRENTTICKRATE
GETMAXTICKRATE
GSPYLITE
SAVEGAME
CANCEL
SOUND_REBOOT
SHOWEXTENTLINECHECK
SHOWLINECHECK
SHOWPOINTCHECK
KDRAW
KSTEP
KSTOP
KSAFETIME
MEMSTAT
CONFIGHASH
EXIT
QUIT
RELAUNCH
DEBUG
DIR
MEM
DUMPNATIVES
GET
SET
OBJ
GTIME
DUMPCACHE
SHOWLOG
TakeFocus
EditDefault
EditActor
CopyToClipboard
HideLog
Preferences
BRIGHTNESS
CONTRAST
GAMMA
PAUSESOUNDS
UNPAUSESOUNDS
STOPSOUNDS
WEAPONRADIUS
ROLLOFF
GRAPH
L2Debug
L2DebugWindow
FLUSH
STAT
CRACKURL
PACKETCOUNTSTART
PACKETCOUNTSTOP
Введя команду PACKETCOUNTSTART, получаем такую статистику:
Нужно больше команд!
Известно, что существуют команды, отдаваемые через чат клиента, например /loc - показывает текущие координаты персонажа. Поэкспериментировав с разными префиксами обнаруживаем, команды с префиксом /// исполняются аналогично введенным в консоли. Кроме того, список xrefs на ParseCommand в IDA намекает, что команд может быть больше, чем мы обнаружили. Еще есть префикс //, используемый для административных команд, и оба эти префикса работают только если у персонажа статус GM-а.
Попробуем аналогично сдампить список команд, введенных с префиксом. Правда оказывается, что ParseCommand также используется движком для обработки команд PlayerPawnMoveTo, CameraYaw и прочих, так что придется помучиться с этим спамом прежде чем получить искомый результат. В итоге получаем вот такой список:
Hidden text
BUTTON
PULSE
TOGGLE
AXIS
JOYPAD
COUNT
KEYNAME
LOCALIZEDKEYNAME
KEYBINDING
L2Restart
Warp
rwarp
MoveWarp
L2WaterInfo
L2WaterReflect
EnterChat
L2EVENTON
L2EVENTOFF
GETITEM
TARGETCHANGE
SHOWCOMPASS
HIDECOMPASS
SCENE0
SCENE1
ANTIPORTAL
TELEPORT
WAITMODECHANGE
MOVEMODECHANGE
CONTROLLERVIEW
PAWNVIEW
SPAWNPLAYERPAWN
DeletePlayer
SPAWNACTOR
SPAWNNPCS
SPAWNPCS
AUTOSPAWNPC
PlayerMove
DumpActor
SPAWNVEHICLES
SPAWNITEM
SPAWNEDPAWNMOVETO
STOPPAWNMOVING
DEFAULTCAMERA
FIXEDDEFAULTCAMERA
TURNBACK
MESHCHANGE
TEXTURECHANGE
DISTANCEFOG
DISTANCEFOGRANGE
PERSPECTIVE
GROUNDSPEEDUP
GROUNDSPEEDDOWN
CAMERAVIEWHEIGHTADJUST
ZOOMINHOLD
ZOOMOUTHOLD
ZOOMINPRESS
ZOOMOUTPRESS
SELECTINGCANCEL
TextCapture
Crash
PLAYERPAWNMOVETO
KEYBOARDBACKMOVESTART
KEYBOARDBACKMOVEFINISH
KEYBOARDMOVESTART
KEYBOARDMOVEFINISH
JOYSTICKMOVE
LEFTTURNINGSTART
LEFTTURNINGFINISH
RIGHTTURNINGSTART
RIGHTTURNINGFINISH
STEPMOVE
COMBOANIMPLAY
CHANGEANIM
CheckGrp
Addabnormal
deleteabnormal
Lodchange
fh
shake
Env Reload
SETTIME
SETTIMERATIO
CancelMAGICTEST
DeleteSelectedActor
pv
PawnViewer
nv
NpcViewer
sv
SkillViewer
Cast
SkillRemain
addcubic
decubic
cubicskill
ATTACKSPEEDDOWN
ATTACKSPEEDUP
setwyvern
SVS
BoneSim
ReduceLOD
KeepMinFrame
SkipAnim
Hitwater
SHADOW
DEFAULTSHADOW
RIDE
UNRIDE
ANIMPLAY
CAMERAPITCH
CAMERAYAW
YAWTURN
TRANSFER
BuildZone
LoadPath
Limit
C_TELEPORT
C_RMODE
GEODATA
SEAMLESS
MAPLOC
SHOWBORDERLINE
SHOWSECTORS
SaveMemInfo
CacheTexture
DUMPRESOURCEHASH
FIRSTCOLOREDMIP
NEARCLIP
D3DRESOURCES
SUPPORTEDRESOLUTION
ISFULLSCREEN
GETPING
INJECT
NETSPEED
LANSPEED
SHOWALL
REPORT
SHOT
SHOWACTORS
HIDEACTORS
RMODE
REND
SHOW
CINEMATICS
CINEMATICSRATIO
FIXEDVISIBILITY
TOGGLEREFRAST
EXEC
SHOWEXTENTLINECHECK
SHOWLINECHECK
SHOWPOINTCHECK
KDRAW
KSTEP
KSTOP
KSAFETIME
OPEN
START
SERVERTRAVEL
DISCONNECT
RECONNECT
EXIT
QUIT
GETCURRENTTICKRATE
GETMAXTICKRATE
GSPYLITE
SAVEGAME
CANCEL
SOUND_REBOOT
SHOWEXTENTLINECHECK
SHOWLINECHECK
SHOWPOINTCHECK
KDRAW
KSTEP
KSTOP
KSAFETIME
MEMSTAT
CONFIGHASH
EXIT
QUIT
RELAUNCH
DEBUG
DIR
MEM
DUMPNATIVES
GET
SET
OBJ
GTIME
DUMPCACHE
SHOWLOG
TakeFocus
EditDefault
EditActor
CopyToClipboard
HideLog
Preferences
BRIGHTNESS
CONTRAST
GAMMA
PAUSESOUNDS
UNPAUSESOUNDS
STOPSOUNDS
WEAPONRADIUS
ROLLOFF
GRAPH
L2Debug
L2DebugWindow
FLUSH
STAT
CRACKURL
PACKETCOUNTSTART
PACKETCOUNTSTOP
STOPMOUSE
MOVEMOUSE
ENDFULLSCREEN
TOGGLEFULLSCREEN
GETCURRENTRES
GETCURRENTCOLORDEPTH
GETCOLORDEPTHS
GETCURRENTRENDERDEVICE
SETRES
TEMPSETRES
Оказывается через клиент доступно гораздо больше команд: 222 из клиента, и только 57 - из консоли! Настало время посмотреть, что же они делают.
Проверяем найденные команды
В списке есть 2 команды телепорта - TELEPORT и C_TELEPORT, очевидно у них должны быть аргументы. Находим в IDA как они парсятся:
.text:104E667E mov ecx, [ebp+arg_0]
.text:104E6681 lea eax, [ebp+var_164]
.text:104E6687 push eax
.text:104E6688 push offset asc_10791768 ; "X="
.text:104E668D push ecx
.text:104E668E call ds:?Parse@@YAHPBG0AAM@Z ; Parse(ushort const *,ushort const *,float &)
.text:104E6694 add esp, 0Ch
.text:104E6697 cmp eax, esi
.text:104E6699 jz loc_104E5DC0
.text:104E669F mov eax, [ebp+arg_0]
.text:104E66A2 lea edx, [ebp+var_160]
.text:104E66A8 push edx
.text:104E66A9 push offset aY ; "Y="
.text:104E66AE push eax
.text:104E66AF call ds:?Parse@@YAHPBG0AAM@Z ; Parse(ushort const *,ushort const *,float &)
.text:104E66B5 add esp, 0Ch
.text:104E66B8 cmp eax, esi
.text:104E66BA jz loc_104E5DC0
.text:104E66C0 mov edx, [ebp+arg_0]
.text:104E66C3 lea ecx, [ebp+var_15C]
.text:104E66C9 push ecx
.text:104E66CA push offset aZ ; "Z="
.text:104E66CF push edx
.text:104E66D0 call ds:?Parse@@YAHPBG0AAM@Z ; Parse(ushort const *,ushort const *,float &)
В принципе это было очевидно - аргументы для телепорта: X=<float> Y=<float> Z=<float>, обе команды работают идентично. Разумеется, нормальный сервер не даст игроку просто так телепортироваться куда угодно - сразу откинет назад, однако на сервере, который не проверяет координаты - все работает.
SHOWLOG, HideLog - открывает и закрывает окно консоли. Альтернатива аргументу /LOG.
Preferences - открывает вот такие настройки:
SPAWNNPCS Num=<int> - спавнит указанное число рандомных мобов вокруг персонажа:
SPAWNPCS Num=<int> - аналогично предыдущей, но спавнит игроков в рандомном шмоте:
RIDE TYPE=<int> - 0 - садимся на страйдера, 1 - на виверну, 2 - на виверну - альбиноса
Правда работает кривовато - после этого клиент практически зависает. Забегая вперед скажу, что маунты есть и в сетевом протоколе, и оно работает!
RMODE, C_RMODE <int> - изменяет режим рендеринга, например на такой
или такой:
SHOWBORDERLINE, SHOWSECTORS - включает это:
SEAMLESS ON/OFF - включает/выключает подгрузку соседних фрагментов карты. Если выключить - соседние фрагменты не будут подгружаться, можно дойти до края земли и упасть:
MAPLOC - выводит в консоль X Y текущего фрагмента карты, например MapX=21, MapY=19 - эльфятник.
GEODATA - пытается грузить файл по пути формата: .\GeoData%d_%d_conv.dat, где числа вместо %d соответствуют координатам MAPLOC. Очевидно, это серверная геодата. Дадим клиенту то, что он хочет - скопируем геодату в System\GeoData. Теперь мы можем взглянуть на мир LA2 глазами сервера:
Видно, что "разрешение" тут гораздо ниже, чем в клиенте - мир состоит из клеток примерно с ширину персонажа, а если точнее - 16x16 координатных единиц (которые отображаются по /loc). Зеленые стрелочки показывают проходимые направления, а красные - непроходимые. А если участок 8x8 клеток не содержит больших перепадов высот и непроходимых направлений - он объединяется в одну большую клетку:
Заключение
Мы познакомились лишь с частью скрытого в клиенте LA2 функционала, часть из которого очевидно была предназначена для тестирования и разработки игры, однако могла пригодиться и игрокам. Однако в клиенте есть ещё кое-что очень интересное. В следующей статье мы выясним, что же делает команда BuildZone.
Комментарии (35)
N1X
07.06.2024 03:27+5Прям ностальгией захлестнуло =) Да, было много часов на "линейку" потрачено...
Помню были еще веселые инструменты вроде Hlapex для модификации трафика с помощью скриптов и HGuard для защиты неофициальных серверов от ботов, при этом автор один и тот же, но первый инструмент позволял обойти второй, правда с некоторыми костылями )
Hint
07.06.2024 03:27+7Пример скрипта для hLaPEx
var pck48: String; hidden: Boolean; i, x, y: Integer; procedure Init; begin hidden := False; pck48 := ''; Randomize; end; procedure SendMsg(msg: String); begin buf := #$4A; WriteD(0); WriteD(2); WriteS('hLaPEx'); WriteS(msg); SendToClient; end; begin if FromServer then Exit; case Ord(pck[1]) of $1B: case Ord(pck[2]) of $05: begin SendMsg('Here I am ;)'); pck := #$30; hidden := False; end; $06: begin if pck48 = '' then Exit; SendMsg('Invisible mode'); hidden := True; pck := pck48; i := 2; x := ReadD(i); y := ReadD(i); x := x + 1000 + Round(Random * 200) - 100; y := y + 1000 + Round(Random * 200) - 100; buf := pck; WriteD(x, 2); WriteD(y, 6); pck := buf; end; end; $48: pck48 := pck; $30: if hidden then pck := ''; end; end.
Позволял в том числе в режиме боя исчезнуть на любое время при нажатии одной кнопки, а потом появиться при нажатии другой. В нужный момент отправляем серверу пакет ValidatePosition с неверными координатами. Сервер думает, что произошел рассинхрон, говорит клиенту переместить персонажа в правильную позицию, скрывает персонажа на время прогрузки. Клиент поправляет позицию и шлет пакет Appearing, который мы блокируем. И сервер начинает ждать нас бесконечно долго, держа невидимыми. Когда готовы, шлем Appearing и появляемся.
Я тогда названия всех программ начинал с буквы h :) Подглядел вроде бы у hd, который так делал (hdGeoEditor и пр.).
XenRE Автор
07.06.2024 03:27У моей версии был авто режим, активирующий локальный телепорт при попытке атаки, и практически дающий бессмертие, если пинг позволяет вовремя реагировать. А еще так можно было замки в соло отжимать.
gruzoveek
07.06.2024 03:27+2У нас играли в нее в компьютерном клубе, причем я честно пытался, наслушавшись восторгов друга. Но не осилил тупо гриндить бегать. Быстро надоело. Переключился на ВОВку.
AgentFire
07.06.2024 03:27Гриндить на х1-х3 было куда менее скучно, одна ошибка и ты ошибся, бегай потом без эсэсок на синих мобах бабло с нуля поднимать. Я уж молчу про возможные ПК из кустов против тебя за место фарма и по фану.
selenzorn
07.06.2024 03:27В 2005 линейка казалась очень крутой: огромные пространства, пвп, куча игроков, торговля, а дома еще не было нормального интернета, но когда первый раз заходишь вов и понимаешь, насколько он ушел вперед — линейку больше не запускаешь
Revertis
07.06.2024 03:27+5У ВОВа графика вырвиглазная по сравнению с Lineage II.
Tsimur_S
07.06.2024 03:27+12Дело не только в мультяшной графике но еще и в реализме мира. Как там в Матрице было? Сначала сделали виртуальный рай но большинство людей в него просто не поверило. Аукцион вместо трейда, какое-то противостояние Орды и Альянса вместо возможности грохнуть кого угодно и за что угодно, инстансы вместо конкуренции за споты и РБ, ПвП на арене ради строчки в рейтинге ПвП на арене, отсутствие полноценной политики и тд.
Я бы не сказал что ВоВ ушел вперед линейки, скорее линейка деградировала свои сильные стороны до ВоВ. Впрочем, на вкус и цвет фломастеры разные. Линейка получила свою популярность, кроме очевидной Кореи, на просторах СНГ, стран LATAM. Видимо было нечто общее в менталитете.
XenRE Автор
07.06.2024 03:27+3Видимо было нечто общее в менталитете.
Я так не думаю. Не забывайте, что мало на каких фришках были рейты x1 - как правило от x3, и вплоть до x1000+. Там, где корейцы задротили - мы получали фан. Ну и как я уже сказал в статье - слив C1 сервера сделал гигантский вклад в популярность именно LA2 - ведь практически все официальные MMO в то время были по схеме pay to play.
Что касаемо мира - до EVE online как до луны. Вот где действительно жестокая галактика и можно всё. А онлайн трейд - очень стрёмное решение, сделанное скорее "на отвали". Особенно если вспомнить, что мало у кого в то время был безлимитный интернет, да и гонять клиент даже на фоне - это такое себе, но тут хоть ог волкер помогал.
Но графика в ВоВ стрёмноватая, тут я согласен. Причем она вроде и сейчас особо лучше не стала.
vanxant
07.06.2024 03:27Не, на ранних фришках было наоборот. Я начинал с рейтов 0.6 (уж очень ГМы хотели денег)
Belking
07.06.2024 03:27А еще когда тебе соклановец на 6 часов идет ману заливать, не вступая в пати, а чтобы ты быстрее прокачался и все это время подбадривает, чтобы ты сам не сдавался. А еще когда отправляешь свою пачку биться с одной из лучших конст топового клана, теряя нафармленный опыт за последние два дня, но потому что нельзя иначе. А еще когда все знают логины-пароли друг друга, и тем кто не может позволить себе ПА можно и скинуться совместно выфармленным. И смиряешься с периодическими крысами, которые считают недельный фарм адены всей пачки украсть себе за радость, а всем и пофиг - ведь лучше когда такие люди себя раньше раскрывают....
Эх, именно в сложности достижения и балансе трат достигнутого и был смысл - что любое действие сопровождалось реальными эмоциями и изменениях во взаимоотношениях...
dartraiden
07.06.2024 03:27Наоборот, у линейки графика какая-то чрезмерно резкая.
Видимо, дело привычки, потому что я вовер с 18-летним стажем, мультяшный стиль привычен и число полигонов у луговой собачки не режет глаз.
SystemOutPrintln
07.06.2024 03:27Не знаю, что в ней такого вырвиглазного.
Благодаря тому же богатству и качеству анимаций мир ВоВа выглядел гораздо живее уже тогда. Тогда как в линеаге 2 и по сей день деревянные болванчики.
daggert
07.06.2024 03:27Не все любят анимешный стиль. Меня это всегда отворачивало от линейки. Ну и огромные пустые пространства…
Firemoon
07.06.2024 03:27Спасибо, что вы не отложили написание статьи в долгий ящик! Всегда интересно заглянуть за кулисы.
0xdead926e
07.06.2024 03:27+5как-то давненько пробовала порендерить карты линейки и столько странноватых решений там увидела... и BSP в режиме "все видят всех" (а потом у них тои/пещера гигантов лагают), и координаты со странными смещениями, и не очень хорошо склеенные тайлы
причем в режиме BSP там только горизонтальные плоские полы, насколько помню. и еще что-то около катакомб/некрополей. та же лесенка перед храмом в гиране- не бсп, а просто моделька.
сопсна результат тех попыток
весь мир целиком в одну сцену тож запихивала, но скринов сходу не нашлось.
XenRE Автор
07.06.2024 03:27+2а потом у них тои/пещера гигантов лагают
Сервер LA2 при определении зоны видимости вокруг персонажа вообще не учитывал координату Z, например с земли можно определить отреспился ли Баюм. По этому естественно все 100500 мобов и игроков в ТОИ, и их взаимодействия, рендерились на клиенте, и особенно осчасливливали тех, у кого был тариф с оплатой за трафик.
причем в режиме BSP там только горизонтальные плоские полы
На сколько я знаю, такова особенность движка Unreal - сначала рендерится однослойный ландшафт - я так понимаю это даже не модель, а просто карта высот, а всё прочее - это уже модельки на нем, т.е. по другому движок не позволяет.
0xdead926e
07.06.2024 03:27сначала рендерится однослойный ландшафт - я так понимаю это даже не модель, а просто карта высот
да, но я не про это. олсо хоть это и не про то, но слоев текстур в ландшафте достаточно много. даже запеченные тени есть, по одной текстуре на каждые два чтоль часа ингейм времени.
еще там есть просто статические модельки и есть отдельно брашмодели. кваки-халфлайфы ковырял? там так же. у брашмоделей есть собственно BSP и флажки видимости какие поверхности видно с текущей.. типа чтоб не рендерить то, что игрок впринципе никак не увидит с текущей позиции. вот, visibility во всех брашмоделях л2- пустая, все видно отовсюду. и технически если бы она была правильной- тои бы это пофиксило даже без изменения сервера.
пример работающей pvs в bsp
камера игрока находится где-то около черной доски слева, и все, что он потенциально не видит- не рендерится вовсе.
XenRE Автор
07.06.2024 03:27Я подробно не исследовал рендеринг, но очевидно, что даже если бы невидимые модельки не рендерились бы, они все равно бы обрабатывались движком - все взаимодействия, проверки на столкновения, движения и скрипты, а еще подгрузка текстур. И самое паршивое, что когда игрок попадает в грид со всей этой пачкой, к нему от сервера прилетает неслабый берст трафика, и клиент начинает все это прогружать, вызывая неслабый фриз. Особенно это радует когда убегаешь от толпы врагов.
Ну и например та же обработка консольных команд - делается тупо сравнением строк. Ни бинарного поиска, ни хешей. А ведь оно не только консольные команды обрабатывает, игровые функции тоже, и используется постоянно.
А касаемо рендеринга ландшафта - кстати визуально работало вполне неплохо, например в вышедшем несколько лет спустя Аионе часто встречается откровенное мыло в ландшафтах в 3 пикселя на метр, а вот в ЛА2 я такого не припоминаю. И я подозреваю тут как раз все делал сторонний движок, так что надо сравнивать с другими играми на UE1.
0xdead926e
07.06.2024 03:27+1даже если бы невидимые модельки не рендерились бы
одно это дало бы очень много. особенно учитывая, что моделька персонажа- на самом деле несколько моделек с разными шейдерами (там отдельно торс, отдельно ноги, отдельно лицо, отдельно волосы...), и канонично для корейских ммо- в модельках персонажей полигонов больше, чем во всем окружении и вот это все. хотя да, пальцы только с камаэлями завезли xD
ну и никто не мешал например ходить по бсп-дереву дважды-трижды (они обычно крайне неглубокие) и нпрмр отсекать все, что после третьего баунса не будет видно. и вообще не просчитывать никак это все. правда да, та же арена баюма была бы невидимой отовсюду и был бы лаг при телепорте туда.. ох вейт, он и так был.
и еще немножко кеков.
вот это- экран логина high five part 4. xD
с другими играми на UE1
емнип в л2 был уе2.5
XenRE Автор
07.06.2024 03:27вообще не просчитывать никак это все
Так нельзя - ведь то, что невидимое сейчас, может стать видимым через секунду. А сервер же не послыалет всю инфу об объектах каждую секунду, т.е. даже нивидимые объекты должны быть загружены и просчитываться, как минимум позиция и состояние.
был бы лаг при телепорте туда.. ох вейт, он и так был.
Любой телепорт, в т.ч. локальный, сопровождается удалением всех объектов и созданием заново, даже если это одни и те же объекты. Т.е. опять все завязано на логику сервера.
емнип в л2 был уе2.5
Возможно.
iRusher
07.06.2024 03:27+2Спасибо большое за статью, отдал этой игре 6 лет, было приятно почитать и однозначно надеюсь что будет цикл статей как запустить свой серв)) это интересно.
Понял что больше наверное не смогу играть в ММО, пока может не выйдет что то достойное на VR, опыт игры л2 стал бременем, после которого все другие онлайн ММО видятся мусором. В каждой игре есть какой то бред, где тебя за ручку водят или ограничивают, где так заботятся что бы не дай бог тебе или кому-то кто-нибудь помешал качаться, или ты расстроился от чего-то. Разработчики выстраивают вокруг тебя забор и контролируют всё что в твоей игре происходит, от такого геймплея несёт стерильностью.
L2 была живым миром, реалистичной моделью общества, суровой и жестокой, но иногда и прекрасной, там можно было встретить как разводил, так и добрых людей, ремесленников, торгашей, мошенников, там можно было нажить врагов которых ненавидишь, и друзей с которыми общаешься по сей день, а часто бывало и так что бывшие враги становятся крепкими друзьями. А политика в линейке это вообще отдельный мир. Это феномен, такой уровень погружения и внедрения в социальную составляющую сервера не даст ни одна игра пока что, ну я по крайней мере пробовал играть в многие проекты, искал замену но ничего из этого не вышло. Так как линейка первая моя ММО, ты постоянно сравниваешь и смотришь на новые игровые миры через призму пережитого в ней опыта.
SystemOutPrintln
07.06.2024 03:27В каждой игре есть какой то бред, где тебя за ручку водят или ограничивают, где так заботятся что бы не дай бог тебе или кому-то кто-нибудь помешал качаться, или ты расстроился от чего-то.
В этом и плюс, что современные ММО стараются дать увлекательный игровой опыт и оградить от всяких неадекватов, цель которых не поиграть, а надоедать другим игрокам грифингом и оскорблениями.
Какие-то ММО идут дальше и предоставляют каждому игроку свой изолированный игровой мир, где невозможно встретить других игроков, пока ты сам этого не захочешь и не пригласишь их. Это просто идеально, никаких тебе малолеток с ником ХХХнагибаторХХХ, которые стилят босса, которого ты бьёшь, и пытаются тебя заПКшить. Никаких малолеток в глобальном чате игры, которые угрожают добраться до чужих мамок.
L2 была живым миром, реалистичной моделью общества, суровой и жестокой
...прямо как реальный мир. А теперь объясните мне, вот зачем уходить в виртуальный мир, который такой же жестокий, токсичный и суровый, как и реальный? Чтобы что?
Напоминает мем "наконец-то моя смена шахтёра закончилась, сейчас приду домой и отдохну, буду копать шахты и добывать алмазы в майнкрафте".
п.с. это я к тому, что вы зря говорите, что "стерильность" геймплея -- это что-то априори плохое.
AgentFire
07.06.2024 03:27+3Плохое плохое. Это как резиновая женщина без отверстий. Это как друг, которого нельзя подкалывать. Это как американские горки, но в VR в мягком кресле дома. Мамкоебы, ПКшеры и лутстилеры - это неотъемлимая часть реализма (не путать с реальностью!). Это необходимый негатив, который увеличивает ценность остального позитива.
Rive
07.06.2024 03:27+1Какие-то ММО идут дальше и предоставляют каждому игроку свой изолированный игровой мир, где невозможно встретить других игроков, пока ты сам этого не захочешь и не пригласишь их.
Впрочем, это уже не ММО, а игра с кооперативным режимом.
Turgere
07.06.2024 03:27Попробуй EVE online. Там песочница ещё глубже и это даёт ещё больше взаимодействия и политики между игроками. Вот там начинается настоящая драма из-за отношений и их последствий, а правила близки к линейке по сути.
norlin
07.06.2024 03:27+2Ууу, спасибо за ностальгию!
После La2 никакие другие типа-ММОшки не заходили вообще, выглядели унылими и скучными. Да и до сих пор разве что Eve Online в плане ммошности лучше реализована, а всё остальное скатилось в сингл-плеер или сессионный ко-оп.
Belking
Так и от WAD'а статью на хабре увидим!