Написание сервера для lineage 2 chronicle 1 на node.js

Новый велосипед будет лучше ? Терпения в начинаниях ))
 
Новый велосипед будет лучше ? Терпения в начинаниях ))
Ну он хотя бы поедет) сейчас ближайшие цели
Перемещение(Игрока, NPC) .
Атака(Игрока, NPC) .

Вектор монет для тестов)
 

Вложения

  • adena cos sin.png
    570,7 КБ · Просмотры: 116
  • adena cos sin 2.png
    380,7 КБ · Просмотры: 116
Есть ли формула для walk speed ? (baseWalkSpd)
Или он всегда 80 для Human Fighter?

С увеличением скорости бега. Скорость шага как-то меняется?
 
Естественно, с добавлением модификаторов скорость бега, и скорость шага - либо увеличиваются, либо уменьшаются, либо вовсе может выдать сообщение( вы не можете двигаться).
1.Первое идет загрузка таблицы параметров PlayableCreature/PC(Играбельного Существа ) -
Таблица
Код:
moving_speed_begin
    FFighter={80; 115; 122; 122; 0; 0; 0; 0}
    MFighter={80; 115; 122; 122; 0; 0; 0; 0}
    FMagic={78; 120; 122; 122; 0; 0; 0; 0}
    MMagic={78; 120; 122; 122; 0; 0; 0; 0}
    FElfFighter={90; 125; 122; 122; 0; 0; 0; 0}
    MElfFighter={90; 125; 122; 122; 0; 0; 0; 0}
    FElfMagic={85; 122; 122; 122; 0; 0; 0; 0}
    MElfMagic={85; 122; 122; 122; 0; 0; 0; 0}
    FDarkelfFighter={85; 122; 122; 122; 0; 0; 0; 0}
    MDarkelfFighter={85; 122; 122; 122; 0; 0; 0; 0}
    FDarkelfMagic={85; 122; 122; 122; 0; 0; 0; 0}
    MDarkelfMagic={85; 122; 122; 122; 0; 0; 0; 0}
    FOrcFighter={70; 117; 122; 122; 0; 0; 0; 0}
    MOrcFighter={70; 117; 122; 122; 0; 0; 0; 0}
    FShaman={70; 121; 122; 122; 0; 0; 0; 0}
    MShaman={70; 121; 122; 122; 0; 0; 0; 0}
    FDwarfFighter={80; 115; 122; 122; 0; 0; 0; 0}
    MDwarfFighter={80; 115; 122; 122; 0; 0; 0; 0}
moving_speed_end
Код обработки
Код:
else if ( !wcscmp(this->parsing_context, L"moving_speed") )
            {
              if ( this->DoubleVector._Mypair._Myval2._Mylast - this->DoubleVector._Mypair._Myval2._Myfirst != 8 )
                CLog::Add(
                  &Log,
                  LOG_ERROR,
                  (wchar_t *)L"%s line[%d], moving_speed int counter is different",
                  g_DataScriptFile_106[56],
                  this->m_lexer.line);
              v25 = this->DoubleVector._Mypair._Myval2._Myfirst;
              LODWORD(v4_8) = (int)v25[4];
              LODWORD(v4) = (int)v25[3];
              LODWORD(v3) = (int)v25[2];
              LODWORD(value_8) = (int)v25[1];
              LODWORD(field) = 32;
              CPCParamDB::SetValueBySRC(
                &g_PCParamDB,
                v86.sex,
                v86.race,
                v86.cls,
                field,
                (int)*v25,
                value_8,
                v3,
                v4,
                v4_8,
                (int)v25[5],
                (int)v25[6],
                (int)v25[7]);
            }

Код:
void __fastcall CPCParamDB::SetValueBySRC(
        CPCParamDB *this,
        int sex,
        int race,
        int fm,
        __int64 field,
        int v1,
        __int64 v2,
        __int64 v3,
        __int64 v4,
        __int64 v5,
        int v6,
        int v7,
        int v8)
{
  double *v13; // rdx
  wchar_t *v1a; // [rsp+30h] [rbp+30h]
  if ( (_DWORD)field == 32 )
  {
    v13 = (double *)((fm + 2 * (race + 30i64 * sex)) << 6);
    v13[58680664] = (double)v1;
    v13[58680668] = (double)(int)v2;
    v13[58680665] = (double)(int)v3;
    v13[58680669] = (double)(int)v4;
    v13[58680666] = (double)(int)v5;
    v13[58680670] = (double)v6;
    v13[58680667] = (double)v7;
    v13[58680671] = (double)v8;
  }
  else
  {
    v1a = _PCParamFieldBySRC[(int)field];
    LODWORD(field) = 1513;
    CLog::Add(
      &Log,
      LOG_ERROR,
      (wchar_t *)L"[%s][%d] Unknown field[%s] setting",
      L"pc_param.cpp",
      field,
      v1a,
      v2,
      v3,
      v4,
      v5);
  }
}
Код:
wchar_t *_PCParamFieldBySRC[37] =
{
  L"PC_INT_DEFAULT",
  L"PC_INT_MIN",
  L"PC_INT_MAX",
  L"PC_STR_DEFAULT",
  L"PC_STR_MIN",
  L"PC_STR_MAX",
  L"PC_CON_DEFAULT",
  L"PC_CON_MIN",
  L"PC_CON_MAX",
  L"PC_MEN_DEFAULT",
  L"PC_MEN_MIN",
  L"PC_MEN_MAX",
  L"PC_DEX_DEFAULT",
  L"PC_DEX_MIN",
  L"PC_DEX_MAX",
  L"PC_WIT_DEFAULT",
  L"PC_WIT_MIN",
  L"PC_WIT_MAX",
  L"PC_BASE_PATTACK",
  L"PC_BASE_CRITICAL",
  L"PC_BASE_ATTACK_TYPE",
  L"PC_BASE_ATTACK_SPEED",
  L"PC_BASE_PDEFEND",
  L"PC_BASE_MATTACK",
  L"PC_BASE_MDEFEND",
  L"PC_BASE_CAN_PENETRATE",
  L"PC_BASE_ATTACK_RANGE",
  L"PC_BASE_DAMAGE_RANGE",
  L"PC_BASE_RAND_DAM",
  L"PC_ORG_HP_REGEN",
  L"PC_ORG_MP_REGEN",
  L"PC_ORG_CP_REGEN",
  L"PC_MOVING_SPEED",
  L"PC_ORG_JUMP",
  L"PC_BREATH_BONUS",
  L"PC_SAFE_FALL_HEIGHT",
  L"PC_COLLISION_BOX"
}; // idb

2.При входе в мир -
,
v12->SendUserInfo(v12, 0i64, 0i64);

присвоение классу CUser/PC(И наследуемому CCreature) значений из таблицы ( но в памяти) , -



long double g_OrgSpeedBySRCME[2][30][2][2][4];
long double __fastcall CPCParamDB::GetOrgSpeed(

CPCParamDB *this,

unsigned int sex,

unsigned int clstype,

unsigned int mt,

EnvType env,

RaceType race)

{

v6 = sex;
if ( sex > 1 || clstype > 0xC0 || mt > 1 || env > ENV_HOVER )
{
CLog::Add(
&Log,
LOG_ERROR,
L"[%s][%d] Some parameter is invalid sex[%d] clstype[%d] movetype[%d] envtype[%d]",
L"pc_param.cpp",
1528,
sex,
clstype,
mt,
env);
return 0.0;
}
else
{
v7 = clstype;
if ( (*(&stru_C69320 + clstype + 1048580) - 4) <= 1 )
v8 = race;
else
v8 = *(&stru_C69028 + clstype + 1048578);
return g_OrgSpeedBySRCME[v6][v8][*(&stru_C69618 + v7 + 1048582)][mt][env];
}

}
User::SetOrgSpeed(
this,
nOrgSpeed0,
&nOrgSpeed0[1],
&nOrgSpeed0[2],
nOrgSpeed4,
&nOrgSpeed4[1],
nOrgSpeed6,
&nOrgSpeed6[1],
&nOrgSpeed7);
[/CODE]

User::SendUserInfo2(this, 0, v49);

3.При Одевании Предмета, Использовании Умения(самим собой, либо целью ) добавление Модификаторов, проверка -
.
4.При движении - проверка (move_to) -
 
Последнее редактирование:
Update


* Перемещение через tasks (создается задача на перемещение по вектору до конечных координат. Персонаж не телепортируется для сервера а идет по шагам.)
* Атака. Проверка на дистанцию. Перемещение. (В работе. Есть моменты, когда не до конца доходит)
 
По поводу движения, рекомендовал бы ознакомиться с такими видео


, для node js должно быть проще такое реализовывать, соответственно и сервера могут быть специфичные .
 
Это уже следующие этапы(pathfind)
 
Как рассчитывается перемещение на сервере? Атака при перемещении.

Само перемещение работает корректно. А если с атакой то есть расхождение.

Я сделал так
* RequestAttack
* Делаю задачу на перемещение. При скорости Human Fighter 126 время между тиками ~900mc
Каждые 900mc идет изменение координат на сервере.
* MoveToLocation (x1... => x2...)
* Когда дистанция 0 (пришли в точку) задача останавливается.
* sendPacket(Attack)

Но на больших или очень малых расстояниях идет рассинхронизация.
То чар ждет перед npc и начинает атаковать через какое-то время то начинает атаку не добегая. Понятно, что время 900mc я сделал путем подбора. Можно конечно привязаться к ValidatePosition (надо копать но вроде он отправляется не только по таймеру но и в момент старта и в момент прихода в конечный пункт)

А как быть с NPC?

1) Как рассчитать время между тиками в ходьбе?
2) Или как иначе синхронизировать ходьбу на клиенте и сервере?
 
Последнее редактирование:
Есть подозрение, что пакетхак ответит на твои вопросы как минимум быстрее и качественнее.

Да не нужно брать Яву или лезть в птс. Восстанавливать алгоритмы пакетного обмена наугад, это просто очень тяжело, т.к там очень много ньюансов. Поэтому, если взять тот же пакетхак, то с ним проще намного какие-то вещи определять, т.к там буквально открыл лог и посмотрел.
 
Реакции: BladeRunner

    BladeRunner

    Баллов: 5
    Человеку нравится страдать, не мешай) разумно было бы найти как сделано в хороших явах, найти в декомпиле птс, и выбрать лучшее решение из найденых. Но тут нет задачи сделать лучше, а надо просто изобрести велосипед ))

но это не даст сразу всей логики рассчета передвижения, а только ее итоговые значения. то есть придется придумывать недостающую часть алгоритма рассчета движения. А еще куча приколюх в виде зависимостей от статов, переходные состояния, и тд. Если все так просто, может тогда и в Луче пакетхаком все легко было выяснить, и зря Мэд уже 3 месяца сидит за математикой движения?
Я нуб, и то прекрасно понимаю, какое колосальное количество логических систем в сервере, которые обдумывать и допиливать надо месяцами, и которые совершенно разные, от мувмента до контроля пакетки, неткода и ваще хз чего. Для меня это все оч странно. я мог бы понять, если бы на примере готовых решений пилилось что-то более быстрое и оптимизированное, собирая лучшее из нескольких вариантов решений. но с нуля ломать себе мозг тем, что и так есть в доступе... честно. не понимаю. хоть закидайте помидорами... тут в жизни и на конкретные задачи нехватает времени, а писать долго, методом тыка, не разбираясь абстракцию... хз... эскапизм чтоли такой. ни па. ни. ма. ю. тупой наверно.... Чел с нуля придумывает законы физики, из принципа не читая учебник...
 
Последнее редактирование:

    rosylik

    Баллов: -6
    затычка в каждой теме
Нашёл в чем проблема. Задача по времени отрабатывает идеально. Осталось формулу подогнать (я так понимаю она линейна)

Проблема была в последней task'e она рандомила)

Мне помог DropItem. Чар пока идёт выкидывает адену.
 
Путем подбора формула времени вызова выглядит специфично но подходит
При 123456 / 126 = 979мс
При 123456 / 500 = 246мс

Так же для теста использую DropItem и если монета падает перед персонажем в бегу то персонаж ее задевает и она к нему "прилипает". Может баг может совпадение но при формулах выше монета падает прям за персонажем тем самым я вижу, что время на клиенте и на сервере идет синхронно. На дальних расстояниях тоже проверил никакого накопительного эффекта и чар и монета двигаются вместе.

Продолжаю наблюдение
 
UPD
Нашел идеальную формулу для бега
125000

125000 / 126 (126 human figther минимальный бег) ~ 992mc
125000 / 500 = 250mc

Даже если взять 125000 / 1000 = 125мс (Такой бег невозможен но синхронизация с аденой(DropItem) *идеальная)

*На старте. Потом происходит лаг пакета. Думаю такое фиксить через validate position чтобы корректировать позицию игрока.
 
Наверное лучше снифануть какие пакеты отправляет птс и сразу все будет проще. Даже наверное по нормальному нужно создавать блок схемы, какие и сколько пакетов шлет птс и в какое время, а дальше просто повторять
 
Тест выполнения атаки только после подхода к npc
(монета падает для теста синхронизации координат клиента и сервера)

 
Промежуточный итог:

Микро-расхождения есть. Связанны со скоростью ходьбы. Сначала персонаж идет и плавно перетекает в бег.

Если сделать скорость шага и бега равной то все тайминги отлично подходят и включаются когда надо.

Какие есть идеи как можно сделать бег по таймеру учитывая начало шага?

Скорость шага: 88
Скорость бега: 126

Задача на бег срабатывает по таймеру каждые 992mc (125000 / 126).
(То есть каждые 992mc на сервере идет изменение координат персонажа)
 

Вложения

  • Диаграмма без названия.drawio.png
    10,6 КБ · Просмотры: 39
UPD
Ответ нашел

Скорость только на старте 88 - 126
Потом персонаж бежит 126 и останавливается сразу.

Первая task должна быть 125000 / 88 = 1420mc
 
Наконец-то разобрался как синхронизировать бег с сервером и клиентом. Написал статью по этому поводу