Я очень долго хотел выложить что-нибудь интересное, но я некоторое время был заблокирован
Собственно кто-то решил изучить область оог, но у многих, как и у меня, пакет читался очень криво, т.е. код для чтения этого пакета был ужасен и в некоторых моментах становился не понятным
Мне пригляделся класс CPWPacket из наработок ворта, но насколько я помню - он был не полон.
В конце концов я написал свой класс, в который входят следующие методы:
Цитата:
GetType() // Возвращает тип текущего пакета
SetType(uint tp) // Задает тип пакету
GetLength() // возвращает длинну буфера
GetShift() // Возвращает значение указателя
GetBuf() // Возвращает весь буфер
ReadUString(bool dword(?)) // Читает длину текста(CUI/Dword) и возвращает сам текст
WriteUString(string text, bool dword(?)) // Записывает длину текста и сам текст в Unicode
ReadAString(bool dword(?)) // Читает текст в формате ANCII
WriteAString(string text, bool dword(?)) // Записывает длину и текст в формате ANCII
WriteData(byte[] buf, bool dword(?)) // записывает длину данных(CUI/Dword), а потом сами данные
ReadData(bool dword(?)) // Читает длину данных и возвращает эти данные
ReadCUInt32() // Возвращает значение CUI
WriteCUInt32(uint value) // Записывает значение CUI
ReadTime(bool swap(?)) // Читает дату и время(swap - флаг(перевернуты ли байт))
WriteFloat(float value, bool swap(?)) // Записывает значение Float(Single)
ReadFloat(bool swap(?)) // Читает значение Float(Single)
ReadInt32(bool swap(?)) // Читает значение Int32
WriteInt32(int value, bool swap(?)) // Записывает значение Int32
ReadDword(bool swap(?)) // Читает значение Dword
WriteDword(uint value, bool swap(?)) // Записывает значение Dword
ReadWord(bool swap(?)) // Читает значение Word
WriteWord(ushort value, bool swap(?)) // Записывает значение Word
WriteArray(byte[] buf, bool swap(?)) // Записывает массив байт в буфер
ReadArray(uint length, bool swap(?)) // Читает массив байт из буфера
WriteByte(byte bt(?)) // Записывает байт(если аргументов 0, то записывается просто нулевой байт)
ReadByte() // Читает 1 байт
Например нам надо прочитать пару байт, дворд и CUI:
public void WriteFloat(float value)
{
WriteFloat(value, false);
}
public float ReadFloat()
{
return ReadFloat(false);
}
public int ReadInt32()
{
return ReadInt32(false);
}
public int ReadInt32(bool swap)
{
return BitConverter.ToInt32(ReadArray(4, swap), 0);
}
public void WriteInt32(int value)
{
WriteInt32(value, false);
}
public void WriteInt32(int value, bool swap)
{
WriteArray(BitConverter.GetBytes(value), swap);
}
public void WriteDword(uint value)
{
WriteArray(BitConverter.GetBytes(value));
}
public void WriteDword(uint value, bool swap)
{
WriteArray(BitConverter.GetBytes(value), swap);
}
public void WriteWord(ushort value)
{
WriteArray(BitConverter.GetBytes(value));
}
public void WriteWord(ushort value, bool swap)
{
WriteArray(BitConverter.GetBytes(value), swap);
}
public uint ReadDword()
{
return BitConverter.ToUInt32(ReadArray(4),0);
}
public uint ReadDword(bool swap)
{
return BitConverter.ToUInt32(ReadArray(4, swap),0);
}
public ushort ReadWord()
{
return BitConverter.ToUInt16(ReadArray(2),0);
}
public ushort ReadWord(bool swap)
{
return BitConverter.ToUInt16(ReadArray(2, swap),0);
}
public void WriteArray(byte[] buf)
{ WriteArray(buf, false); }
public void WriteArray(byte[] buf, bool swap)
{
if (swap) Array.Reverse(buf);
for (int i = 0; i < buf.Length; i++)
WriteByte(buf[i]);
}
public byte[] ReadArray(uint length)
{ return ReadArray(length, false); }
public byte[] ReadArray(uint length, bool swap)
{
byte[] ret = new byte[length];
for (int i = 0; i < length; i++)
ret[i] = ReadByte();
if (swap) Array.Reverse(ret);
return ret;
}
public void WriteByte()
{
WriteByte(0x00);
}
public void WriteByte(byte bt)
{
buffer.Add(bt);
}
public byte ReadByte()
{
if (shift >= buffer.Count)
{
Console.WriteLine("shift >= buffer.Count");
return 0x00;
}
byte ret = buffer[(int)shift];
shift++;
return ret;
}
}
}
________________ Для просмотра ссылок или изображений в подписях, у Вас должно быть не менее 10 сообщение(ий). Сейчас у Вас 0 сообщение(ий). - твинки любого игрока, их дата создания, последний онлайн, статус удаления и прочее
Skype - freepvps
ICQ - 412705115
[Ссылки могут видеть только зарегистрированные пользователи. ] - ставкобот [Ссылки могут видеть только зарегистрированные пользователи. ] - общение в КЧ через смартфон
class MoveStopImpl
{
public:
enum { ID = 0x0007 };
Coord3D pos;
byte orientation;
byte moveType;
WORD seqNum;
byte chkSum, qIdx;
WORD speed;
protected:
template<int mode> void format(Serializer<mode> & s)
{
s.fr(pos.x_).fr(pos.z_).fr(pos.y_)
.wr(speed).b(orientation).b(moveType)
.wr(seqNum).b(chkSum).b(qIdx);
}
};
typedef FragmentGiSpec<MoveStopImpl> FragmentGiMoveStop;
собственно, для описания пакета больше ничего не нужно. Весь остальной код работает чисто с этим классом, а раскладыванием пакетов занимаются две отдельные фабрики. Плюс объявление работает в обе стороны - т.е. пакет как и разбирается по этим правилам, так и может быть собран обратно в массив байт.
Магия С++
собственно, для описания пакета больше ничего не нужно. Весь остальной код работает чисто с этим классом, а раскладыванием пакетов занимаются две отдельные фабрики. Плюс объявление работает в обе стороны - т.е. пакет как и разбирается по этим правилам, так и может быть собран обратно в массив байт.
Магия С++
Магия прямых рук
Сами имеем схожую систему чтения / обработки пакетов.
Хочется обратить внимание тех, кто читает эту тему, что данный подход является чертовски правильным и ничего лучше пока никто не придумал
Не следует мешать в кучу пакет, как сущность и поток данных, который вычитываем. Разделение наглядно видно в приведенном во 2ом посте коде.
Последний раз редактировалось Kitsune; 21.04.2012 в 22:03.
byte[] bt = new byte[2];
uint dword;
uint cui;
public void Read(Packet P)
{
P.ReadArray(bt).ReadDword(dword).ReadCUInt32(cui);
}
Я так понимаю?)
________________ Для просмотра ссылок или изображений в подписях, у Вас должно быть не менее 10 сообщение(ий). Сейчас у Вас 0 сообщение(ий). - твинки любого игрока, их дата создания, последний онлайн, статус удаления и прочее
Skype - freepvps
ICQ - 412705115
[Ссылки могут видеть только зарегистрированные пользователи. ] - ставкобот [Ссылки могут видеть только зарегистрированные пользователи. ] - общение в КЧ через смартфон
Пакет, это результат чтение данных из потока, а не средство для чтения данных.
Я через отдельный метод записываю каждый полученный байт, а этот метод создает пакет(Packet)(записывает тип, длинну, а потом данные пакета), разделяет эти байт, и передает его через евент
Далее я уже читаю из этого Packet все нужные мне данные и создаю другой пакет
Иными словами:
Код:
public void WriteByte(byte bt)
{
try
{
if (!CheckCUInt32(bttype.ToArray()))
{
bttype.Add(bt);
return;
}
if (!CheckCUInt32(btlen.ToArray()))
{
btlen.Add(bt);
if (CheckCUInt32(btlen.ToArray()))
{
len = ReadCUInt32(btlen.ToArray());
if (len > 0) return;
}
else
return;
}
if (btbuf.Count < len) btbuf.Add(bt);
if (btbuf.Count == len)
{
uint type = ReadCUInt32(bttype.ToArray());
byte[] buf = btbuf.ToArray();
Packet P = new Packet();
P.SetType(type);
P.WriteArray(buf);
btbuf.Clear();
bttype.Clear();
btlen.Clear();
len = 0;
client.Read(P);
if(P.GetType() == 0x00)
{
Packet[] Packs = GetContainer(P);
for (int i = 0; i < Packs.Length; i++)
client.ReadContainer(Packs[i]);
}
}
}
catch { }
}
Добавлено через 3 часа 54 минуты
Видимо я правильно понял)
В примере Slik переменная s - класс пакета
Метод fr(FloatRead) на C# мог бы выглядеть вот так:
public Packet fr(out float value)
{
value = BitConverter.ToSingle(ReadArray(4));
return this;
}
________________ Для просмотра ссылок или изображений в подписях, у Вас должно быть не менее 10 сообщение(ий). Сейчас у Вас 0 сообщение(ий). - твинки любого игрока, их дата создания, последний онлайн, статус удаления и прочее
Skype - freepvps
ICQ - 412705115
[Ссылки могут видеть только зарегистрированные пользователи. ] - ставкобот [Ссылки могут видеть только зарегистрированные пользователи. ] - общение в КЧ через смартфон
Последний раз редактировалось FreePVP))); 22.04.2012 в 21:59.
Причина: Добавлено сообщение
ну как-то так, да. Более того, само описание фрагмента задает формат для содержимого фрагмента, а ответственность за форматирование контейнеров, 00-22, и прочих деталях находятся в других похожих местах. Более того, с помощью такого описания контролируется и необходимая длина данных для формирования фрагмента при помощи специального сериализатора, который только считает длину
Добавлено через 4 минуты
ну и потом, можно делать более веселые штуки, например такие
Код:
class PlayerPurchaseItemImpl
{
public:
enum { ID = 0x0048 };
struct Item
{
DWORD id;
DWORD unk;
WORD count;
WORD slot;
byte tradeSlot; // tradeSlot is a slot in market list of <22><A9>.
// Slots are not reordered after sell/buy.
template<int mode> void format(Serializer<mode> & s)
{
s.lr(id).lr(unk).wr(count).wr(slot).b(tradeSlot);
}
};
DWORD moneyLost;
DWORD unk;
BYTE unk2;
std::vector<struct Item> items;
protected:
template<int mode> void format(Serializer<mode> & s)
{
s.lr(moneyLost).lr(unk).b(unk2).arr(items, &Serializer<mode>::wr);
}
};
Последний раз редактировалось silk; 24.04.2012 в 00:29.
Причина: Добавлено сообщение
Пакет, это результат чтение данных из потока, а не средство для чтения данных.
Эммм... Вопросик Вам - а чего бы не инкапсулировать туда же логику обработки данного пакета ?
В противном случае не вижу профита плодить десятки классов на каждый пакет, учитывая, что нужно он один единственный раз - получить его из потока. Дальше его данные обрабатываются и пакет освобождается.
При таком раскладе пакет - как средство чтения и десериализации данныых - самое то. Вот как-то так :
Код:
procedure TCharacterController.HandleS00_105RoleLockInfo(pck : TSubPacket);
var
b : byte;
begin
// byte - lock status (0=disabled, 1=enabled)
b := pck.ReadByte();
if b = 1 then self._locked := true else self._locked := false;
// dword - lock end timestanmp
self._lockEndTimestamp := pck.ReadDword();
// dword - lock duration
self._lockDuration := pck.ReadDword();
end;
учитывая, что TSubPacket сделан по аналогии с классом автора.
Последний раз редактировалось vogel; 26.04.2012 в 20:59.
Я делал сначала что-то подобное
В итоге получилась куча методов в одну строку
________________ Для просмотра ссылок или изображений в подписях, у Вас должно быть не менее 10 сообщение(ий). Сейчас у Вас 0 сообщение(ий). - твинки любого игрока, их дата создания, последний онлайн, статус удаления и прочее
Skype - freepvps
ICQ - 412705115
[Ссылки могут видеть только зарегистрированные пользователи. ] - ставкобот [Ссылки могут видеть только зарегистрированные пользователи. ] - общение в КЧ через смартфон