Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Rewrite PacketEncoder #9

Closed
2 of 4 tasks
blackphreak opened this issue Apr 27, 2020 · 1 comment
Closed
2 of 4 tasks

Rewrite PacketEncoder #9

blackphreak opened this issue Apr 27, 2020 · 1 comment
Assignees
Labels
documentation Improvements or additions to documentation enhancement New feature or request Packet Related

Comments

@blackphreak
Copy link
Owner

blackphreak commented Apr 27, 2020

[Not yet complete, wait until I have time to finish this thought ^_^ @ 2020-May-11 19:11 UTC+8]
To enhance the PacketEncoder efficiency and to provide packets sync to web packet parser
(pktParser), I have the following ideas:

  1. Rewrite PacketEncoder with memory stream
    • MemoryStream (ref: stackoverflow)
    • Add functions to append (/build/concat) packet to MemoryStream
  2. Write parser to parse packets from PacketEncoder from c# -> to WebPacketParser
    (additional info can be written using comment after each data in packet)
    Longer packet header must be placed at the beginning of the key-value database
    (Detail will be listed on 2nd floor of this thread)

Additional enhancement for parser:

  • Identify the format string format [See: Issues 17]
  • Auto gen _pkt.js after git push
@blackphreak blackphreak added the enhancement New feature or request label Apr 27, 2020
@blackphreak blackphreak self-assigned this Apr 27, 2020
@blackphreak blackphreak changed the title Rewrite Packets with Structs Rewrite PacketEncoder May 10, 2020
@blackphreak
Copy link
Owner Author

blackphreak commented May 11, 2020

[Finally Completed @ 2020-June-04 23:37 UTC+8]

For Comments

  1. Desc: data name
  2. Deprecated L: data length (unit: byte), any = unlimited length until reached 00
  3. T: data type (optional), tell the parser to show as that type, not as uint
    default UNum (4-byte), values: Num, UNum (unsigned number), GBK
  4. // either R / Fn, not both:
    1. R: data reference (optional), values: MAP, NPC, ITEM, SKILL, FS (formatstring)
    2. Fn: special data function (optional), display data using function (provide JS function name)
      if the functionName is ".writeFormat", auto parse the latter data as format parameters.
      auto assign the index of parameters to support arbitrary order of format string
      (eg: ^2 @3 ^4 |1 $5)
  5. Mark: special mark, values:
    1. REPEAT_START: allow parser to repeat the format starting from this
    2. REPEAT_END: allow parser to repeat the format within range (start & end)
    3. EOP (FLAG_EOP): tell the parser: this is the end of packet, use only when the packet has no body (means: header and/or subcate only).
  6. To / Here: For JS_F ONLY , values:
    1. To: this packet continues in that file , marked with <fragment_name>
      JS_F: To[Feather_Server/Entity/PlayerRelated/HeroBasicInfo.cs,Hero_Basic_Info]
    2. Here: the packet continues here, with the <fragment_name> mark ONLY
      JS_F: Here[Hero_Basic_Info]

For JS Marks

  1. JS_D
    • Delimeter start
    • Avaliable Tags:
      • Desc (Must)
      • Mark[EOP]
  2. JS_SC
    • SubCate
    • Avaliable Tags:
      • Desc (Must)
      • (Either one)
        • PT
      • (Either one)
        • Jump[<start_mark>,<continue_mark>]
        • Mark[EOP]
      /* JS_SC: 01 Jump[JS_J_A,JS_CONT] Desc[Example For Subcate Jump] */
      /* JS_SC: PT Jump[JS_J_B,JS_CONT] Desc[Example For Pattern Jump] */
      /* JS_SC: 02 Desc[Example For End Of Packet] Mark[EOP] */
  3. JS_J_#
    • Jump point for SubCate
    • Avaliable Tags:
      • Jump[<start_mark>,<continue_mark>]
  4. JS_F
    • Code Fragment
    • Note: Identify the end by "}" with indentation level - 1 (end of toFragment function)
    • Note: every FragmentMark must be a unique locator in the source file. (No duplicate mark is allowed)
    • Set jump to this fragment
      JS_F: To[<fragmentMark>@<sourceCodeFullPath>]
      JS_F: To[Hero_Basic_Info@Feather_Server/Entity/PlayerRelated/HeroBasicInfo.cs]
    • Set fragment begins
      JS_F: Here[<fragmentMark>]
      JS_F: Here[Hero_Basic_Info]
  5. JS
    • packet datas
    • Avaliable Tags:
      • Desc (Must)
      • T
      • (Either) R (Or) Fn
      • Mark[REPEAT_START]
      • Mark[REPEAT_END]
  6. TODO: [Attribute=Disable]

For Parser

setDelimeter(<pktHeader>)       // <- count the pkt header length (3901 = 2 bytes)
writePadding(<sz>)              // <- add 00 * sz (size in byte), writePadding(2) = 2 bytes = "0000"
writeByte(<>)                   // 1-byte data (auto convert to little-endian before transmission)
writeWord(<>)                   // 2-byte data (auto convert to little-endian before transmission)
writeDWord(<>)                  // 4-byte data (auto convert to little-endian before transmission)
writeString(<strHere>)          // <- must be GBK

writeParam(<dataHere>)          // <- only usable after writeFormat(...) // the data will always be 4-byte long.
writeString(<strHere>)          // <- must be GBK, length will be auto counted (73<4 bytes size><actual string>)

Code Example

public static PacketStreamData loginSuccess()
{
    return new PacketStream()
        /* JS_D: Desc[Login Success] */
        .setDelimeter(Delimeters.LOGIN_SUCCESS)
        /* JS: Desc[Padding] */
        .writePadding(4)
        .pack();
}

public static PacketStreamData HeroPreviews(HeroBasicInfo[] players, bool isInHeroCreation = false)
{
    var stream = new PacketStream();

    if (isInHeroCreation)
    {
        stream
            /* JS_D: Desc[Hero Creation] */
            .setDelimeter(Delimeters.HERO_CREATION)
            /* JS: Desc[unk1] */
            .writeDWord(0xBFCAE4CE)
            .nextPacket();
    }

    for (byte i = 1; i <= 6; i++)
    {
        if (i - 1 >= players.Length || players[i - 1] == null)
        {
            // same signature will be found below, so no need to fill this format.
            stream
                .setDelimeter(Delimeters.LOGIN_HERO_VIEW)
                .writeByte(i)
                .writePadding(49)
                .writeFormat(EFormatString.TEMPLATE_LOGIN_NAME)
                .writeString(" ")
                .writeParam(0x0)
                .nextPacket();
        }
        else
        {
            stream
                /* JS_D: Desc[Login Hero View] */
                .setDelimeter(Delimeters.LOGIN_HERO_VIEW)
                /* JS: Desc[Slot Index] */
                .writeByte(i)

                /* JS_F: To[Hero_Basic_Info@Feather_Server/Entity/PlayerRelated/HeroBasicInfo.cs] */
                .writeFragment(players[i - 1])
                .nextPacket();
        }
    }

    return stream.pack();
}

public static PacketStreamData setEntityTitle(Entity e, TitleCate type)
{
    var stream = new PacketStream();
    /* JS_D: Desc[Entity Title (Currently Using)] */
    stream.setDelimeter(Delimeters.ENTITY_TITLE_CURRENT);
    /* JS: Desc[EntityID] */
    stream.writeDWord(e.ID);
    /* JS: Desc[Padding] */
    stream.writePadding(1);
    
    /* JS: Desc[FormatID] */
    stream.writeFormat(ParamLib.getFormatStringIDByTitleCate(type));

    /* JS_SC: PT Jump[JS_J_A,JS_CONT] Desc[Title Only] */
    /* JS_SC: PT Jump[JS_J_B,JS_CONT] Desc[Colored Title] */
    /* JS_SC: PT Jump[JS_J_C,JS_CONT] Desc[Colored Title with GBK] */
    /* JS_SC: PT Jump[JS_J_D,JS_CONT] Desc[Gang Title with Role (Gang Name, Role, Pos)] */
    /* JS_SC: PT Jump[JS_J_E,JS_CONT] Desc[GBK raw text] */
    switch (type)
    {
        case TitleCate.TITLE_ONLY:
            /* JS_J_A */
            /* JS: Desc[Title] R[FS] */
            stream.writeParam(0x1234);
            /* JS_J_A_END */
            break;
        case TitleCate.COLORED_TITLE:
            /* JS_J_B */
            /* JS: Desc[Color] */ // TODO: parser for arbitrary color code formatting
            stream.writeParam(0xFF00FF); // hex color code
            /* JS: Desc[Title] R[FS] */
            stream.writeParam(0x1234);
            /* JS_J_B_END */
            break;
        case TitleCate.COLORED_TITLE_WITH_GBK:
            /* JS_J_C */
            /* JS: Desc[Title] */
            stream.writeString("GBK String Here");
            /* JS: Desc[Color] */
            stream.writeParam(0x1234);
            /* JS_J_C_END */
            break;
        case TitleCate.GANG_TITLE_WITH_ROLE:
            /* JS_J_D */
            /* JS: Desc[Gang Name] */
            stream.writeString("GBK String Here");
            /* JS: Desc[Player Role] R[FS] */
            stream.writeParam(ParamLib.getFormatStringIDByPlayerRole(player.role));
            /* JS: Desc[Gang Pos] R[FS] */
            stream.writeParam(0x1234);
            /* JS_J_D_END */
            break;
        case TitleCate.ARBITRARY:
            /* JS_J_E */
            /* JS: Desc[Title] */
            stream.writeString("GBK String Here");
            /* JS_J_E_END */
            break;
    }

    /* JS_CONT */
    return stream.pack();
}

public static PacketStreamData TaskLog(Hero player, TaskSubCate taskType)
{
    var stream = new PacketStream();
    /* JS_D: Desc[TaskLog] */
    stream.setDelimeter(Delimeters.TASK_LOG)

    if (taskType == TaskSubCate.BEINGS
        || taskType == TaskSubCate.DISPLAY)
    {
        /* JS_SC: 00 Desc[Begins] Mark[EOP] */
        /* JS_SC: 09 Desc[Display] Mark[EOP] */
        stream.writeSubCate(taskType);
        return stream.pack();
    }

    /* JS_SC: 01 Jump[JS_J_A,JS_CONT] Desc[Normal Task Avaliable] */
    /* JS_SC: 02 Jump[JS_J_A,JS_CONT] Desc[Special Task Avaliable] */
    /* JS_SC: 04 Jump[JS_J_A,JS_CONT] Desc[Task Not-Avaliable] */
    if (taskType == TaskSubCate.TASK_AVALIABLE_NORM
        || taskType == TaskSubCate.TASK_AVALIABLE_SPEC
        || taskType == TaskSubCate.TASK_AVALIABLE_END)
        stream.writeSubCate(taskType);

    /* JS_J_A */
    /* JS: Desc[unk1] */
    stream.writeWord(0x1122)
    /* JS: Desc[unk2] */
        .writeWord(0x1122)
    /* JS: Desc[Lv. Req.] */
        .writeByte(0x01)
    /* JS: Desc[Task Tried] */
        .writeByte(0x01)
    /* JS: Desc[Max Try Allowed] */
        .writeByte(0x01)
    /* JS: Desc[Padding] */
        .writePadding(1)
    /* JS: Desc[FormatID] */
        .writeFormat(0x1234)
    /* JS: Desc[Task Cate] R[FS] */
        .writeParam(0x1234)
    /* JS: Desc[Task Name] R[FS] */
        .writeParam(0x1234)
    /* JS: Desc[Task Duration] R[FS] */
        .writeParam(0x1234)
    /* JS: Desc[Task NPC] R[FS] */
        .writeParam(0x1234)
    /* JS: Desc[Task MAP] R[FS] */
        .writeParam(0x1234)
    /* JS: Desc[NPC X] */
        .writeParam(0x1234)
    /* JS: Desc[NPC Y] */
        .writeParam(0x1234);
    /* JS_J_A_END */

    /* JS_CONT */
    return stream.pack();
}

public static PacketStreamData setPlayerEffects(Hero player)
{
    var stream = new PacketStream();
    /* JS_D: Desc[Player Effect(s)] */
    stream.setDelimeter(Delimeters.SELF_PA) // PLAYER_EFFECTS
    /* JS: Desc[entityID] */
        .writeDWord(player.ID);

    foreach (PlayerEffect eff in player.effects)
    {
        /* JS: Desc[ani. ID] Fn[E_AniID] Mark[REPEAT_START] */
        stream.writeDWord(eff.ID)
        /* JS: Desc[ani. duration] Fn[E_AniDuration] */
            .writeByte(eff.duration)
        /* JS: Desc[ani. layer] Fn[E_AniLayer] Mark[REPEAT_END] */
            .writeByte(eff.layer);
    }
    return stream.pack();
}

@blackphreak blackphreak added this to the Rewrite PacketEncoder milestone May 11, 2020
@blackphreak blackphreak added documentation Improvements or additions to documentation Packet Related labels May 17, 2020
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request Packet Related
Projects
None yet
Development

No branches or pull requests

1 participant