Ru-MaNGOS

Ru-MaNGOS (http://mangos.ytdb.ru/index.php)
-   Патчи (http://mangos.ytdb.ru/forumdisplay.php?f=6)
-   -   [patch/dev] Refer-A-Friend System (http://mangos.ytdb.ru/showthread.php?t=3354)

MaS0n 02.01.2011 16:56

[patch/dev] Refer-A-Friend System
 
Вложений: 2
Собственно, патч, реализующий оффлайк систему "Пригласи друга"
Не совершенство, скорее бета-версия, но все же, ниже поясню почему

Немного теории
Услуга включает в себя 3 основые фишки - призвать друга, повысить уровень и утроенный опыт. Третью часть можно отбросить, это делается целиком на сервере.

Призвать друга

Опция при клике на портрете друга в пати и синий шарик во френд-листе. Кстати в 3.3.5 он выставляется независимо от статуса друга, и, позволю себе поправить уважаемого TOM_RUS в посте http://ru-mangos.ru/showpost.php?p=8598&postcount=4, это не флаг, а все-таки статус, проверял в дебаге клиента на 2.4.3., тем более если структура FriendInfo соотв. близз структуре в памяти, то по смещению pointer + 1 хранится как раз таки статус
Код:

struct FriendInfo
{
    FriendStatus Status;
    uint32 Flags;
    uint32 Area;
    uint32 Level;
    uint32 Class;

Ну сейчас это не актуально, просто так, к слову.

Проблема была вот с чем, я писал в той теме, что не мог получить гуид того, кого нужно призвать, не выделяя его. Проблема "легко" решилась, когда я подетальнее разобрал lua функцию SummonFriend - там до каста спелла, если цель не в прямой видимости, а вызывается допустим через тот же шарик, шлется пакет под номером 317 - CMSG_SET_SELECTION

Код:

    v8 = 0;
    if ( stru_BD07B0.guid_low != v3 || stru_BD07B0.guid_high != v2 )
    {
      v8 = 1;
      sub_518DC0(v3, v2);
    }
    Spell_C__CastSpell(dword_BE7D88, 0, v3, v2, 0);
    if ( v8 )
    {
      sub_518DC0(stru_BD07B0.guid_low, stru_BD07B0.guid_high);
      return 0;
    }

sub_518DC0 - это и есть отправка пакета с нужным нам гуидом.

Повысить уровень

Основная проблема заключалась в том, что опция активировалась только при опр. условиях, и их удалось найти, опять же подебажив клиент и рассмотрев смещения полей в структурах

После проходв кучи проверок доходим до такой проверки, где результат либо 0, либо 3 , 0 - это верно, 3 - вернет ошибку

Код:

result = *(_BYTE *)(*((_DWORD *)v13 + 1026) + 4197) < 1u ? 3 : 0;
А проверяется тут байт, по смещению 1 в поле(PLAYER_FIELD_BYTES в мангосе), или флаг 0x100
Код:

.text:006DEB02                mov    ecx, [esi+1008h]
.text:006DEB08                cmp    byte ptr [ecx+1065h], 1

Оцениваем патч, смотрим код, т.к там есть хаки, например на EFFECT_SUMMON_PLAYER, текущие проверки CheckCast не поддерживают призыв друга совсем, на выставление флагов связывания и активации дарения уровня и т.д

Предлагайте свои варианты, т.к очень хотелось бы довести патч до официального репозитория

Да, и я использовал отдельную таблицу для реферского(приглашающего) аккаунта и 5 реферралов(приглашенных) - мб тоже какой-то более рациональный способ есть

Ниже патч и sql - работает система просто, добавляем в таблицу ID аккаунта рефера и ID аккаунтов реферралов. Вынесение опций в конфиг, высылку на почту жевры/ракеты и прочую мелкую косметику не делал, если будет необходимость, с радостью сделаю.

Ну и все замечания и предложения по патчу рассмотрю внимательно :)
А так же отписывайтесь об ошибках, я мог позабыть что-то включить в патч, а сейчас проверить не могу
С Новым Годом :)

ghostpast 02.01.2011 17:43

Код:

QueryResult *result = WorldDatabase.Query("SELECT refer_id, referral_id1, referral_id2, referral_id3, referral_id4, referral_id5, grantable_levels FROM refer_a_friend_table");
судя по коду атрибут grantable_levels должен быть в таблице characters.
Тут учитывается такие факта:
1. уровень другу можно поднять только до 60 уровня
2. аккаунты могут быть связаны только на 3 месяца ?

а вообще желательна такая таблица в БД realmd
PHP код:

CREATE TABLE `account_friend` (
  `
idint(11unsigned NOT NULL default '0',
  `
friend_idint(11unsigned NOT NULL default '0',
  `
binding_datebigint(40),
  `
expires_datebigint(40),
   
PRIMARY KEY  (`id`)
ENGINE=InnoDB DEFAULT CHARSET=utf8

Получение списка персонажей друзей
PHP код:

SELECT guidlevel
FROM characters
WHERE account IN 
(SELECT friend_id FROM account_friend WHERE id = <id_аккаунта> AND expires_date < <текущая_дата>); 


MaS0n 02.01.2011 18:02

Спасибо, перезалил патч, мой косяк
Нет, количество подарочных уровней должно хранится на чаре, который их зарабатывает.

Уровень 60 ограничен клиентом, проверка на поднятия уровня выше 60 на сервере тоже имеется(вдруг читеры додумаются обойти клиент :))

Ограничение времени связки аккаунтов не делал, если надо, то сделать не проблема

Насчет таблицы - в реалмд перенести можно, но все равно надо 5 полей для френдов, т.к на оффе можно 5 друзей пригласить, или как-то хранить 5 ИД акков в одном поле, а-ля бывшая data в БД чаров

ПС : чуть позже выложу еще для 2.4.3 версию, т.к отличается тем, что нужно выставлять статус во френд-листе, что в этом патче не делается, я писал выше почему

ghostpast 02.01.2011 18:11

Цитата:

Сообщение от MaS0n (Сообщение 17917)
Спасибо, перезалил патч, мой косяк
Нет, количество подарочных уровней должно хранится на чаре, который их зарабатывает.

Уровень 60 ограничен клиентом, проверка на поднятия уровня выше 60 на сервере тоже имеется(вдруг читеры додумаются обойти клиент :))

Ограничение времени связки аккаунтов не делал, если надо, то сделать не проблема

Насчет таблицы - в реалмд перенести можно, но все равно надо 5 полей для френдов, т.к на оффе можно 5 друзей пригласить, или как-то хранить 5 ИД акков в одном поле, а-ля бывшая data в БД чаров

насчет подарочных уровней у меня нет возражений.

с точки зрения теории нормализации моя таблица подойдет - количество друзей в ней неограничено: каждая запись соответствует одному другу. проверять их количество можно в самом коде. еще можно вынести эту опцию в конфиг (если это не ограничение клиента).

ограничение времени у меня уже учтено в запросе на списке друзей, достаточно подставлять текущую дату и id приглашающего (либо проверять при запуске сервера). также можно сделать опцию в конфиге

MaS0n 02.01.2011 18:24

Цитата:

Сообщение от ghostpast (Сообщение 17918)
насчет подарочных уровней у меня нет возражений.

с точки зрения теории нормализации моя таблица подойдет - количество друзей в ней неограничено: каждая запись соответствует одному другу. проверять их количество можно в самом коде. еще можно вынести эту опцию в конфиг (если это не ограничение клиента).

ограничение времени у меня уже учтено в запросе на списке друзей, достаточно подставлять текущую дату и id приглашающего. также можно сделать опцию в конфиге

Ага, я так понял :
мой вариант (рефер и 5 френдов)
1 2 3 4 5 6

твой вариант ( рефер и 5 френдов)
1 2
1 3
1 4
1 5
1 6

Ну тогда в твоей таблице не должно быть PRIMARY KEY ('id'), этот ключ делает значение уникальным

ghostpast 02.01.2011 18:28

Цитата:

Сообщение от MaS0n (Сообщение 17919)
Ага, я так понял :
мой вариант (рефер и 5 френдов)
1 2 3 4 5 6

твой вариант ( рефер и 5 френдов)
1 2
1 3
1 4
1 5
1 6

Ну тогда в твоей таблице не должно быть PRIMARY KEY ('id'), этот ключ делает значение уникальным

действительно, не заметил сразу
PHP код:

CREATE TABLE `account_friend` (
  `
idint(11unsigned NOT NULL default '0',
  `
friend_idint(11unsigned NOT NULL default '0',
  `
binding_datebigint(40),
  `
expires_datebigint(40),
   
PRIMARY KEY  (`id`, `friend_id`)
ENGINE=InnoDB DEFAULT CHARSET=utf8


TOM_RUS 02.01.2011 19:53

Цитата:

Сообщение от MaS0n (Сообщение 17913)
это не флаг, а все-таки статус

FriendStatus это маска из флагов, в т.ч. и RAF
Код:

struct FriendInfo
{
  _BYTE Connected;
  _BYTE Status;
  _BYTE f2[2];
  const char *Name;
  _BYTE Note[512];
  WGUID Guid;
  signed int Level;
  _DWORD Class;
  _DWORD AreaId;
  _DWORD dword21C;
};

Код:

signed int __cdecl Lua_GetFriendInfo(int a1)
{
  signed int result; // eax@3
  FriendInfo *fInfo; // edi@6
  int v3; // eax@8
  char *v4; // ebx@9
  int v5; // eax@10
  int v6; // ebx@12
  const char *v7; // eax@13
  DWORD v8; // ecx@13
  WGUID v9; // ST18_8@13
  int v10; // eax@13
  int v11; // eax@17
  int v12; // ecx@19
  int v13; // eax@20
  int v14; // eax@23
  const char *v15; // ecx@26
  char status; // al@32
  char *v17; // eax@33
  char *v18; // eax@35
  const char *v19; // [sp+4h] [bp-1Ch]@14
  WGUID v20; // [sp+14h] [bp-Ch]@5
  char *v21; // [sp+1Ch] [bp-4h]@9

  if ( !FrameScript__IsNumber(a1, 1) && !FrameScript__IsString(a1, 1) )
  {
    FrameScript__DisplayError(a1, "Usage: GetFriendInfo(index or name)");
    return 0;
  }
  if ( FrameScript__IsNumber(a1, 1) )
  {
    v20 = (WGUID)(signed __int64)FrameScript__ToNumber(a1, 1);
    if ( v20.guid_low - 1 <= 100 )
      fInfo = (FriendInfo *)((char *)dword_C79F98 + 544 * (v20.guid_low - 1));
    else
      fInfo = 0;
  }
  else
  {
    v3 = FrameScript__ToLString(a1, 1, 0);
    fInfo = (FriendInfo *)GetFriendInfoByName(dword_C79F98, v3);
  }
  v4 = FrameScript__GetText("UNKNOWN", -1, 0);
  v21 = v4;
  if ( !fInfo )
  {
    FrameScript__pushnil(a1);                  // name
    FrameScript__PushNumber(a1, 0.0);          // level
    FrameScript__PushString(a1, v4);            // class
    FrameScript__PushString(a1, v4);            // area
    FrameScript__pushnil(a1);                  // connected
    FrameScript__PushString(a1, &byte_9E14FF);  // status
    FrameScript__pushnil(a1);                  // note
    FrameScript__pushnil(a1);                  // RAF
    return 8;
  }
  FrameScript__PushString(a1, fInfo->Name);    // name
  FrameScript__PushNumber(a1, (double)fInfo->Level);// level
  v5 = fInfo->Class;
  if ( v5 < g_ChrClassesDB.minIndex
    || v5 > g_ChrClassesDB.maxIndex
    || (v6 = g_ChrClassesDB.Rows[v5 - g_ChrClassesDB.minIndex], !v6) )
  {
    v7 = v21;
    goto LABEL_16;
  }
  v8 = fInfo->Guid.guid_low;
  v20.guid_low = 0;
  v20.guid_high = 0;
  v9.guid_high = fInfo->Guid.guid_high;
  v9.guid_low = v8;
  v10 = DbNameCache_GetInfoBlockById(&WDB_CACHE_NAME, *(_QWORD *)&v9, (int)&v20, 0, 0, 0);
  v7 = (const char *)sub_72AAB0(0, v10);
  if ( v7 )
  {
LABEL_16:
    v19 = v7;
    goto LABEL_17;
  }
  v19 = *(const char **)(v6 + 16);
LABEL_17:
  FrameScript__PushString(a1, v19);            // class
  v11 = fInfo->AreaId;
  if ( v11 < g_AreaTableDB.minIndex )
    goto LABEL_46;
  if ( v11 > g_AreaTableDB.maxIndex )
    goto LABEL_46;
  v12 = g_AreaTableDB.Rows[v11 - g_AreaTableDB.minIndex];
  if ( !v12 )
    goto LABEL_46;
  v13 = *(_DWORD *)(v12 + 8);
  if ( v13 )
  {
    if ( v13 >= g_AreaTableDB.minIndex )
    {
      if ( v13 <= g_AreaTableDB.maxIndex )
      {
        v14 = g_AreaTableDB.Rows[v13 - g_AreaTableDB.minIndex];
        if ( v14 )
          v12 = v14;
      }
    }
  }
  if ( v12 )
    v15 = *(const char **)(v12 + 44);
  else
LABEL_46:
    v15 = v21;
  FrameScript__PushString(a1, v15);            // area
  if ( fInfo->Connected )
    FrameScript__PushNumber(a1, 1.0);          // connected
  else
    FrameScript__pushnil(a1);                  // connected
  if ( !fInfo->Connected )
    goto LABEL_36;
  status = fInfo->Status;
  if ( !(status & 4) )
  {
    if ( status & 2 )
    {
      v18 = FrameScript__GetText("CHAT_FLAG_AFK", -1, 0);
      FrameScript__PushString(a1, v18);        // status
      goto LABEL_37;
    }
LABEL_36:
    FrameScript__PushString(a1, &byte_9E14FF);  // status
    goto LABEL_37;
  }
  v17 = FrameScript__GetText("CHAT_FLAG_DND", -1, 0);
  FrameScript__PushString(a1, v17);            // status
LABEL_37:
  if ( fInfo->Note[0] )
    FrameScript__PushString(a1, fInfo->Note);  // note
  else
    FrameScript__pushnil(a1);                  // note
  if ( fInfo->Status & 8 )
  {
    FrameScript__PushNumber(a1, 1.0);          // RAF
    result = 8;
  }
  else
  {
    FrameScript__pushnil(a1);                  // RAF
    result = 8;
  }
  return result;
}


MaS0n 02.01.2011 20:25

Большое спасибо за разьяснение, но я имел в виду это
Код:

enum FriendStatus
{
    FRIEND_STATUS_OFFLINE  = 0,
    FRIEND_STATUS_ONLINE    = 1,
    FRIEND_STATUS_AFK      = 2,
    FRIEND_STATUS_UNK3      = 3,
    FRIEND_STATUS_DND      = 4
};

enum SocialFlag
{
    SOCIAL_FLAG_FRIEND      = 0x01,
    SOCIAL_FLAG_IGNORED    = 0x02,
    SOCIAL_FLAG_MUTED      = 0x04,                          // guessed
    SOCIAL_FLAG_RAF        = 0x08                          // Recruit-A-Friend
};

Правильнее, по-моему мнению, надо

Код:

enum FriendStatus
{
    FRIEND_STATUS_OFFLINE  = 0,
    FRIEND_STATUS_ONLINE    = 1,
    FRIEND_STATUS_AFK      = 2,
    FRIEND_STATUS_UNK3      = 3,
    FRIEND_STATUS_DND      = 4,
    FRIEND_STATUS_RAF        = 8                                // Recruit-A-Friend
};

enum SocialFlag
{
    SOCIAL_FLAG_FRIEND      = 0x01,
    SOCIAL_FLAG_IGNORED    = 0x02,
    SOCIAL_FLAG_MUTED      = 0x04,                          // guessed
};

И в вышеприведенной функции
Код:

  if ( fInfo->Status & 8 )
  {
    FrameScript__PushNumber(a1, 1.0);          // RAF
    result = 8;
  }

Ну и в самом пакете SMSG_CONTACT_LIST флаги и статус - разные вещи
Код:

      CDataStore__GetInt64(v4, (int)&v36); // guid
      CDataStore__GetInt32(v4, (int)&v33); // flags
      CDataStore__GetString(v4, (int)&v23, 0x200u); // note
      if ( v33 & 1 ) // if flags & SOCIAL_FLAG_FRIEND
      {
        v28 = 0;
        v31 = 0;
        v32 = 0;
        CDataStore__GetInt8(v4, (int)&v37); // status
        v8 = v37;
        if ( v37 )
        {
          CDataStore__GetInt32(v4, (int)&v28); // area
          CDataStore__GetInt32(v4, (int)&v31); // level
          CDataStore__GetInt32(v4, (int)&v32); // class
          v8 = v37;
        }

Код:

        data << uint64(itr->first);                        // player guid
        data << uint32(itr->second.Flags);                  // player flag (0x1-friend?, 0x2-ignored?, 0x4-muted?)
        data << itr->second.Note;                          // string note
        if(itr->second.Flags & SOCIAL_FLAG_FRIEND)          // if IsFriend()
        {
            data << uint8(itr->second.Status);              // online/offline/etc?
            if(itr->second.Status)                          // if online
            {
                data << uint32(itr->second.Area);          // player area
                data << uint32(itr->second.Level);          // player level
                data << uint32(itr->second.Class);          // player class
            }
        }

Да, и в начале пакета сервер шлет семерку, как 1|2|4, что соответствует сигналам для интерфейса
x & 1 - friend list update
x & 2 - ignored list update
x & 4 - muted list update

Восьмерки там нет, и клиент такое не обрабатывает

И надо дропнуть
Код:

FRIEND_STATUS_UNK3 = 3
Т.к не используется и смысл для маски ошибочен

TOM_RUS 02.01.2011 20:55

Да, перепутаны флаги статуса и списка, FRIEND_STATUS_UNK3 вообще лишний.

MaS0n 03.01.2011 18:26

Выложу завтра-послезавтра с ограничением времени, а так же сделаю вариант с реалмд таблицей

TOM_RUS, закоммитили бы эти исправления :)

rsa 07.01.2011 20:01

Во первых спасибо за работу.
Решил попробовать запустить этот патч. Сразу возникла куча вопросов.
1. Список слинкованных аккаунтов грузится только при старте сервера. Это по идее так? А если аптайм месяц?
2. Фичи слинкованных аккаунтов работают только в пати. Ограничение в коде патча. Так и должно быть?
3. Приглашенный уже не может быть приглашающим и наоборот? По коду либо то либо другое.
4. Почем не использован штатный SetSelectionGuid()? Есть причины, может я чего-то не понимаю? Потому что если его использовать то весь код из spell.cpp и spelleffect.cpp просто не нужен.

Fedia22 07.01.2011 20:05

Цитата:

Сообщение от rsa (Сообщение 18116)
2. Фичи слинкованных аккаунтов работают только в пати. Ограничение в коде патча. Так и должно быть?

так и должно быть... на оффе только так

Den 07.01.2011 20:13

Цитата:

Сообщение от rsa (Сообщение 18116)
1. Список слинкованных аккаунтов грузится только при старте сервера. Это по идее так? А если аптайм месяц?

А если сделать команду: reload этой таблицы ? Может быть, я чего то не понял...

rsa 07.01.2011 20:55

Цитата:

Сообщение от Den (Сообщение 18118)
А если сделать команду: reload этой таблицы ? Может быть, я чего то не понял...

ну во первых эту команду еще надо сделать, а во вторых я уже переделал, список грузится при загрузке чара и совсем другим путем.
Новый вопрос - бонусные уровни даются приглашающему каждый второй левел до 60? Или я неправильно понял код? То есть 80-му пару левелов на "лишней" экспе для приглашенного не набить?

Fedia22 07.01.2011 21:09

да даётся всего до 60 лвла, дальше уже ни как....

Den 07.01.2011 22:26

Цитата:

А если сделать команду: reload этой таблицы ?
Стало интересно...
Правильно будет работать ?

rsa 07.01.2011 23:56

вроде будет. только это дурная мысль изначально - что, ГМ будет сидеть в игре, сканить таблицу и перезагружать ее ручками как кто-то рефера поставит? да и вообще хранение линков в objectmgr изначально неэкономично, и сделанный тут поиск - кошмар системщика ;)
я уже все это сделал вроде нормально, с конфигом и рейтами, потестирую и через пару дней тут положу...

Mr.Grom 08.01.2011 08:10

Создаем твинка на 2м акке и в 2 окна его качаем с бонусными рейтами, от этого есть защита?
Или договариваемся кому надо прокачать твинка и качаем по очереди, надо проверку на отсутствие акаунта у приглашенного на сервере. У близзов каждый акк надо оплачивать, а тут наделают акков и вперед твинков качать.

rsa 08.01.2011 11:38

Цитата:

Сообщение от Mr.Grom (Сообщение 18138)
Создаем твинка на 2м акке и в 2 окна его качаем с бонусными рейтами, от этого есть защита?
Или договариваемся кому надо прокачать твинка и качаем по очереди, надо проверку на отсутствие акаунта у приглашенного на сервере. У близзов каждый акк надо оплачивать, а тут наделают акков и вперед твинков качать.

нет от этого защиты на фришардах, принципиально нет. можно только ограничить число регистраций с одного ИП, но тоже не поможет.
Крайний вопрос остался, может кто-то все же знает - приглашенный сам кого-то может пригласить? И как в таком случае ведет себя RAF система? И может ли быть у одного приглашенного несколько приглашающих?
Я пока сделал ограничение по числу приглашенных и приглашающих на аккаунт через конфиг. Народ сам разберется.

MaS0n 08.01.2011 11:54

Я тоже переделал загрузку информации о RAF и вынес некоторые опции в конфиг, так же реализовал истечение времени услуги через 3 месяца, но выложить пока не могу, во-первых еще тестирую, во-вторых - сессия.

Отвечаю на вопросы :

- насчет нерациональности хранения и загрузки информации в курсе, моей целью было заложить основу, работу пакетов, основных аспектов, а уже потом дорабатывать для принятия в офф. репо. Там, кстати выставление дин. флагов тоже нерационально, их надо слать где-то в BuildUpdateBlockForPlayer

- фичи слинкованных аккаунтов и в клиенте работают только в пати, я на всякий случай вкрутил проверки против читеров

- в самом клиенте стоит ограничение в 60, опции отключаются после 60 уровня, мой код - проверки против читеров

- про приглашенного и приглашающего, скорей всего нет, я руководствовался этой статьей - http://eu.blizzard.com/support/artic...rticleId=31211

- его бесполезно использовать, т.к если в пати например у нас 2 друга, при суммоне например через шарик во френд-листе, НЕ ВЫДЕЛЯЯ того, кого хотим суммонить, верный гуид отсылается ОДИН РАЗ через этот пакет (CMSG_SET_SELECTION), после чего тут же идет 0 гуид


ПС : там кстати краш возможен, при выделении моба
Код:

diff --git a/MiscHandler.cpp b/MiscHandler.cpp
index 5be3b1e..8da1110 100644
--- a/MiscHandler.cpp
+++ b/MiscHandler.cpp
@@ -408,6 +408,9 @@ void WorldSession::HandleSetSelectionOpcode( WorldPacket & recv_data )
    if (!unit)
        return;
 
+    if (_player->IsReferAFriendLinked(((Player*)unit)) && !_player->isSummonFriendNeedSelect())
+        _player->SetSummonFriendGuid(guid);
+
    if(FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction()))
        _player->GetReputationMgr().SetVisible(factionTemplateEntry);
 }

надо
Код:

diff --git a/MiscHandler.cpp b/MiscHandler.cpp
index 5be3b1e..8da1110 100644
--- a/MiscHandler.cpp
+++ b/MiscHandler.cpp
@@ -408,6 +408,9 @@ void WorldSession::HandleSetSelectionOpcode( WorldPacket & recv_data )
    if (!unit)
        return;
 
+    if (unit->GetTypeId() == TYPEID_PLAYER)
+    {
+        if (_player->IsReferAFriendLinked(((Player*)unit)) && !_player->isSummonFriendNeedSelect())
+            _player->SetSummonFriendGuid(guid);
+    }
+
    if(FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction()))
        _player->GetReputationMgr().SetVisible(factionTemplateEntry);
 }


ghostpast 08.01.2011 12:44

Цитата:

Сообщение от rsa (Сообщение 18141)
Крайний вопрос остался, может кто-то все же знает - приглашенный сам кого-то может пригласить? И как в таком случае ведет себя RAF система?

может, но только после ввода полноценного ключа.
А - приглашающий
Б - приглашенный А
В - приглашенный Б
когда в группе только (А и Б) или (Б и В) - работает как написано выше.
случаи, когда в группе А, Б и В не встречал
когда в группе только А и В - никаких бонусов нет
Цитата:

Сообщение от rsa (Сообщение 18141)
И может ли быть у одного приглашенного несколько приглашающих?

может.на e-mail высылается ключ, который вводится вместо пробного ключа. соответственно 2 раза активировать приглашение на одном аккаунте не получится. после активиции приглашения у приглашающего количество возможных приглашений увеличивается на 1. (то есть изначально доступно 5 приглашений. когда приглашаем друга их остается 4. после ввода ключа количество приглашений снова 5)

rsa 08.01.2011 12:50

Цитата:

Сообщение от MaS0n (Сообщение 18143)
- про приглашенного и приглашающего, скорей всего нет, я руководствовался этой статьей - http://eu.blizzard.com/support/artic...rticleId=31211

- его бесполезно использовать, т.к если в пати например у нас 2 друга, при суммоне например через шарик во френд-листе, НЕ ВЫДЕЛЯЯ того, кого хотим суммонить, верный гуид отсылается ОДИН РАЗ через этот пакет (CMSG_SET_SELECTION), после чего тут же идет 0 гуид

[/code]

понятно, значит про приглашенного-приглашающего инфы нет. ладно, делаю возможным оба варианта.
не очень понятно в чем проблема. ну нулевой, так проще его не назначать и все. у меня работает, безо всего этого геморроя в spell.cpp
а вот с отсылкой флага надо что-то решать. пока флаг не проявляется пока друга "в натуре" не увидеть, а это не есть хорошо.

MaS0n 08.01.2011 12:59

Ну не знаю, если не сейвить гуид игрока куда-то кроме curSelection можем получить 2 бага, первый, когда каст начинается, присылается на селект нулевой гуид, и если вы сумоните игрока, не видя его в прямой видимости, будет ересь

Второй, если тип во время каста суммона (10 секунд) захочет потыкать мышкой в мобов или других игроков, селект снова заменится черт знает чем

rsa 08.01.2011 13:22

Цитата:

Сообщение от MaS0n (Сообщение 18146)
Ну не знаю, если не сейвить гуид игрока куда-то кроме curSelection можем получить 2 бага, первый, когда каст начинается, присылается на селект нулевой гуид, и если вы сумоните игрока, не видя его в прямой видимости, будет ересь

Второй, если тип во время каста суммона (10 секунд) захочет потыкать мышкой в мобов или других игроков, селект снова заменится черт знает чем

если следовать вашей логике, то саммон через камень призыва невозможен в принципе - там используется тот же код и селекшн в процессе не путается. да даже если и сменится - ну значит игрок сам виноват, нефиг тыкать куда ни попадя.

Fedia22 08.01.2011 15:36

сумон идёт даже если человек не выбран в таргет, сумонить можно только в пати, если сумон до конца не прошёл, а я прервал каст (пробежался или ещё что либо) то вешается часовой КД...

MaS0n 08.01.2011 16:08

Дааа, похоже я ошибся и с шариком, и в общем, когда далеко френды друг от друга, дин. флаги не работают, и в листе шарика нету. Так что вышеприведенные правки весьма актуальны

Так же, мне удалось разыскать флаг 0x100, про который я знаю, что он является условием в пати/группе при отсутствии прямой видимости. Но только он не шлется в SMSG_GROUP_LIST, а шлется в SMSG_PARTY_MEMBER_STATS_FULL.

Код:

enum GroupMemberOnlineStatus
{
    MEMBER_STATUS_OFFLINE  = 0x0000,
    MEMBER_STATUS_ONLINE    = 0x0001,
    MEMBER_STATUS_PVP      = 0x0002,
    MEMBER_STATUS_UNK0      = 0x0004,                      // dead? (health=0)
    MEMBER_STATUS_UNK1      = 0x0008,                      // ghost? (health=1)
    MEMBER_STATUS_UNK2      = 0x0010,                      // never seen
    MEMBER_STATUS_UNK3      = 0x0020,                      // never seen
    MEMBER_STATUS_UNK4      = 0x0040,                      // appears with dead and ghost flags
    MEMBER_STATUS_UNK5      = 0x0080,                      // never seen
+  MEMBER_STATUS_2_RAF    = 0x0100                        // RAF status in party/raid, is correct status??? or flag???
};

Я его нашел почти сразу, но поле uint8 заставило меня усомнится, что он шлется в SMSG_GROUP_LIST, т.к этот флаг - 0x100 = 256 выходит за пределы uint8.
Покопав еще немного, я выяснил его истинное место
Код:

    data << uint32(mask1);                                  // group update mask
    data << uint16(MEMBER_STATUS_ONLINE);                  // member's online status
    data << uint32(player->GetHealth());                    // GROUP_UPDATE_FLAG_CUR_HP
    data << uint32(player->GetMaxHealth());                // GROUP_UPDATE_FLAG_MAX_HP
    data << uint8(powerType);                              // GROUP_UPDATE_FLAG_POWER_TYPE
    data << uint16(player->GetPower(powerType));            // GROUP_UPDATE_FLAG_CUR_POWER
    data << uint16(player->GetMaxPower(powerType));        // GROUP_UPDATE_FLAG_MAX_POWER
    data << uint16(player->getLevel());                    // GROUP_UPDATE_FLAG_LEVEL
    data << uint16(player->GetZoneId());                    // GROUP_UPDATE_FLAG_ZONE
    data << uint16(player->GetPositionX());                // GROUP_UPDATE_FLAG_POSITION
    data << uint16(player->GetPositionY());                // GROUP_UPDATE_FLAG_POSITION

Причем как я понял, это дополнение к основному статусу, ведь там всегда слалась единица, ну с RAF будет 1 | 256(0x01 | 0x100)


ПС - насчет селекшн я пока все равно не понимаю, сохранить корректный селект гуид для последующей активации эффекта 152 и эффекта суммона невозможно в текущих условиях, имхо

rsa 08.01.2011 16:24

Цитата:

Сообщение от MaS0n (Сообщение 18160)
Дааа, похоже я ошибся и с шариком, и в общем, когда далеко френды друг от друга, дин. флаги не работают, и в листе шарика нету. Так что вышеприведенные правки весьма актуальны

Так же, мне удалось разыскать флаг 0x100, про который я знаю, что он является условием в пати/группе при отсутствии прямой видимости. Но только он не шлется в SMSG_GROUP_LIST, а шлется в SMSG_PARTY_MEMBER_STATS_FULL.

ПС - насчет селекшн я пока все равно не понимаю, сохранить корректный селект гуид для последующей активации эффекта 152 и эффекта суммона невозможно в текущих условиях, имхо

упс. а я уже закончил основную часть ;)
https://github.com/rsa/mangos/commit...17c36832159e00
ладно, попробую сейчас эти флаги тоже сделать, спасибо за исследование.
нормально работает без допсохранения гуидов, а насчет тыкать пока кастится - ну можно затычку сделать чтоб не менялся селект во время каста. только зачем? пускай игроки привыкают ручками не шалить.

MaS0n 08.01.2011 16:30

вносить так и так придется :) без этого вне прямой видимости опции даже не появляются, тестил на 2 персах, один в Тераморе, другой в Эльвине был

Насчет шарика во френд-листе я терь совсем теряюсь, если флаги в группе верны - шарик во френд листе появляется опять-таки сам, если персы рядом и в зоне видимости, опять сам, нужен или не нужен статус я так и не понял, но раз близы его проверяют, то думаю пригодится ;)
ВОт здесь вся инфа об этом - http://ru-mangos.ru/showpost.php?p=17927&postcount=8

ПС - кажется понял, сначала проверяется прямая видимость, если ок - выход с возвратом 1, потом группа/рейд, точно так же и только потом уже френд-лист, так что лучше статус делать :)

rsa, просмотрел коммит, отлично, спс за участие, думаю доведем патч до офф. репо :)

rsa 08.01.2011 16:36

Цитата:

Сообщение от MaS0n (Сообщение 18163)
вносить так и так придется :) без этого вне прямой видимости опции даже не появляются, тестил на 2 персах, один в Тераморе, другой в Эльвине был

Насчет шарика во френд-листе я терь совсем теряюсь, если флаги в группе верны - шарик во френд листе появляется опять-таки сам, если персы рядом и в зоне видимости, опять сам, нужен или не нужен статус я так и не понял, но раз близы его проверяют, то думаю пригодится ;)
ВОт здесь вся инфа об этом - http://ru-mangos.ru/showpost.php?p=17927&postcount=8

шарик появляется по динфлагам если в видимости. и не пропадают, портался чаром в инст и звал оттуда - пашет. а вот вне видимости - может групфлаг поможет?
Так. Проверил, групфлаг пашет хотя как-то странно, не до конца понял. Но в разных зонах при создании пати шарик активируется. А вот при загрузке - не всегда. Ну и так уже отлично просто. Правка:
https://github.com/rsa/mangos/commit...044c681b660337

MaS0n 08.01.2011 16:42

Угу, поможет, но лучше и статус прокидывать во френд-листе - я думаю, просто на всякий случай :)

rsa 08.01.2011 16:54

Давайте нужные флаги - допишу :) Я не игрок и сам ничего не сниффаю, поэтому без той работы что вами проделана сам бы хрен чего сваял.

TOM_RUS 08.01.2011 16:58

Код:

enum GroupMemberFlags
{
    MEMBER_STATUS_OFFLINE  = 0x0000,
    MEMBER_STATUS_ONLINE    = 0x0001,                      // Lua_UnitIsConnected
    MEMBER_STATUS_PVP      = 0x0002,                      // Lua_UnitIsPVP
    MEMBER_STATUS_DEAD      = 0x0004,                      // Lua_UnitIsDead
    MEMBER_STATUS_GHOST    = 0x0008,                      // Lua_UnitIsGhost
    MEMBER_STATUS_PVP_FFA  = 0x0010,                      // Lua_UnitIsPVPFreeForAll
    MEMBER_STATUS_UNK3      = 0x0020,                      // used in calls from Lua_GetPlayerMapPosition/Lua_GetBattlefieldFlagPosition
    MEMBER_STATUS_AFK      = 0x0040,                      // Lua_UnitIsAFK
    MEMBER_STATUS_DND      = 0x0080,                      // Lua_UnitIsDND
    MEMBER_STATUS_RAF      = 0x0100,                      // Lua_IsReferAFriendLinked
    MEMBER_STATUS_UNK4      = 0x0200,                      // something to do with vehicles
};

Код:

char __stdcall Is_RAF_Player(WGUID guid)
{
  void *v1; // eax@1
  unsigned int v2; // eax@2
  GroupMemberInfo *groupInfo; // eax@3
  SosialInfo *socialInfo; // eax@8

  v1 = ClntObjMgrGetObjectPtr(guid, TYPEMASK_PLAYER, ".\\Player_C.cpp", 15314);
  if ( v1 )
  {
    v2 = (*(_DWORD *)(*((_DWORD *)v1 + 62) + 356) >> 6) & 1;// UNIT_DYNAMIC_FLAGS & 0x40
  }
  else
  {
    groupInfo = (GroupMemberInfo *)GetPartyMemberInfoByGuid((int)&guid);
    if ( (groupInfo || (groupInfo = (GroupMemberInfo *)GetRaidMemberInfoByGuid(&guid)) != 0)
      && groupInfo->StatusFlags & 0x100 )
    {
      LOBYTE(v2) = 1;
    }
    else
    {
      if ( g_socialList && (socialInfo = (SosialInfo *)GetSocialInfoByGuid(g_socialList, *(_QWORD *)&guid)) != 0 )
        v2 = ((unsigned int)socialInfo->SocialFlags >> 3) & 1;// SocialFlags & 0x08
      else
        LOBYTE(v2) = 0;
    }
  }
  return v2;
}


MaS0n 08.01.2011 17:07

Для шарика/френд-листа

SocialMgr.h

Код:

enum FriendStatus
{
    FRIEND_STATUS_OFFLINE  = 0,
    FRIEND_STATUS_ONLINE    = 1,
    FRIEND_STATUS_AFK      = 2,
-  FRIEND_STATUS_UNK3      = 3,
    FRIEND_STATUS_DND      = 4,
+  FRIEND_STATUS_RAF      = 8
};

enum SocialFlag
{
    SOCIAL_FLAG_FRIEND      = 0x01,
    SOCIAL_FLAG_IGNORED    = 0x02,
    SOCIAL_FLAG_MUTED      = 0x04,                          // guessed
-  SOCIAL_FLAG_RAF        = 0x08                          // Recruit-A-Friend
};

SocialMgr.cpp

Код:

    for(PlayerSocialMap::iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr)
    {
        sSocialMgr.GetFriendInfo(plr, itr->first, itr->second);

        data << uint64(itr->first);                        // player guid
        data << uint32(itr->second.Flags);                  // player flag (0x1-friend?, 0x2-ignored?, 0x4-muted?)
        data << itr->second.Note;                          // string note
        if(itr->second.Flags & SOCIAL_FLAG_FRIEND)          // if IsFriend()
        {
            data << uint8(itr->second.Status);              // online/offline/etc?
            if(itr->second.Status)                          // if online
            {
                data << uint32(itr->second.Area);          // player area
                data << uint32(itr->second.Level);          // player level
                data << uint32(itr->second.Class);          // player class
            }
        }
    }

Где-то перед выделенным местом надо отсылать добавочную 0x8 для RAF

PS - ну я не снифал, это чистые раскопки клиента :)

rsa 08.01.2011 17:45

Цитата:

Сообщение от MaS0n (Сообщение 18170)
Для шарика/френд-листа

SocialMgr.h

Где-то перед выделенным местом надо отсылать добавочную 0x8 для RAF

PS - ну я не снифал, это чистые раскопки клиента :)

поскольку уже решили что статус - это маска флагов, то не перед этим а в этом. только тогда работу со статусом придется переделать...

TOM_RUS 08.01.2011 17:49

Надо
Код:

void SocialMgr::GetFriendInfo(Player *player, uint32 friend_lowguid, FriendInfo &friendInfo)
исправить.

MaS0n 08.01.2011 18:19

Угу, в этой функции хорошо статус присвоить
Кстати, а он в ней верно присваивается, не должна быть маска с онлайн статусом и афк/днд?
Типа вот так
Код:

        friendInfo.Status = FRIEND_STATUS_ONLINE;
        if(pFriend->isAFK())
-            friendInfo.Status = FRIEND_STATUS_AFK;
+            friendInfo.Status |= FRIEND_STATUS_AFK;
        if(pFriend->isDND())
-            friendInfo.Status = FRIEND_STATUS_DND;
+            friendInfo.Status |= FRIEND_STATUS_DND;

ПС : кстати надо переназвать функцию, это не FriendInfo, а SocialInfo, т.к друга определяет SocialFlag

TOM_RUS, мне кажется что SocialInfo и FriendInfo, которую вы выкладывали чуть раньше, это одинаковые структуры, и назватся она должна именно SocialInfo. У вас SocialFlags в этой функции неверны, а та структура идеально подходит :)

rsa 08.01.2011 22:31

С учетом изложенного по флагам:
https://github.com/rsa/mangos/commit...517a01e7282ddc
осталась косметика, уже не принципиальная (вывод списка и тому подобное).

Softer 09.01.2011 00:27

Вопрос: если призываешь друга который выше тебя по левелу - каст должен проходить или нет?

selector 09.01.2011 07:00

Небольшой баг-репортик.
Цитата:

Как влияет правило утроенного опыта на состояние отдыха?

Пока вы играете в группе с приглашенным, состояние отдыха не тратится. Применяется только правило утроенного опыта.
По коду не увидел данное..

Цитата:

Да, но всего на 10%. Данное повышение действует лишь при убийстве монстров, дающих репутацию с определенной фракцией. Репутация за выполнение заданий или другие действия не увеличивается данным бонусом.

Для получения бонусной репутации должны выполняться те же правила, что и для тройного опыта.
Тоже не нашел правки в коде


Дальше там шла ифна о прогулочной ракете. Само собой у нас никаких тайм-карт нету и оплаты тоже. Появилась идея - при достижении приглашенного игрока 60лвл, ракета будет выдана пригласившему(в конфиге можно добавить опцию).

rsa 09.01.2011 07:32

Цитата:

Сообщение от Softer (Сообщение 18222)
Вопрос: если призываешь друга который выше тебя по левелу - каст должен проходить или нет?

В патче ограничений нет.

Добавлено через 3 минуты
Цитата:

Сообщение от selector (Сообщение 18227)
Дальше там шла ифна о прогулочной ракете. Само собой у нас никаких тайм-карт нету и оплаты тоже. Появилась идея - при достижении приглашенного игрока 60лвл, ракета будет выдана пригласившему(в конфиге можно добавить опцию).

там не только ракета, еще какие-то лошади вроде должны быть. только это сложно будет - у нас как известно карт нет, поэтому френд-статус может плавать туда-сюда.
а вот с репутацией надо подумать еще...


Текущее время: 11:37. Часовой пояс GMT +3.

ru-mangos.ru - Русское сообщество MaNGOS