hardcode or resource?

Results 1 to 10 of 10
  1. #1
    Enthusiast Int16 is online now
    MemberRank
    Oct 2022 Join Date
    33Posts

    hardcode or resource?

    So.. im basically pretty new to the flyff source and c++ is not my main language but im trying to get more understanding of it and to practice im currently working on a teleporter that reads data from the resource

    rough example :

    Code:
    //Location      //Coordinates           //Desc.                 //min lv    //max lv    //CD    //mover for drop info
    "Flarine"       (232323,2323234,242332) FLARINE_DESCRIPTION     =           =           =       =
    "The Wilds"     (444444,444,4444)       "the wilds yo"          80          120         3600    MI_BESIBIGFOOT02
    
    but the teleporter itself is not the topic i need help with
    my question would be if its save to use stuff like teleport coordinates inside the resource

    i just feel like storing data like this inside client folder screams "exploitable".

    and how does the flyff.a /flyff.b system works is it really that save?

    All i need is some enlightenment about the resource xD thats the only thing i dont really understand right now

    thanks in advance


  2. #2
    ‎‎‎‎ Ketchup is offline
    ModeratorRank
    Jan 2009 Join Date
    New YorkLocation
    2,833Posts
    Quote Originally Posted by Int16 View Post
    So.. im basically pretty new to the flyff source and c++ is not my main language but im trying to get more understanding of it and to practice im currently working on a teleporter that reads data from the resource

    rough example :

    Code:
    //Location      //Coordinates           //Desc.                 //min lv    //max lv    //CD    //mover for drop info
    "Flarine"       (232323,2323234,242332) FLARINE_DESCRIPTION     =           =           =       =
    "The Wilds"     (444444,444,4444)       "the wilds yo"          80          120         3600    MI_BESIBIGFOOT02
    
    but the teleporter itself is not the topic i need help with
    my question would be if its save to use stuff like teleport coordinates inside the resource

    i just feel like storing data like this inside client folder screams "exploitable".

    and how does the flyff.a /flyff.b system works is it really that save?

    All i need is some enlightenment about the resource xD thats the only thing i dont really understand right now

    thanks in advance
    .a & .b are both client and resource and if i recall there was a tool awhile back that allowed you to bypass the md5 hash.

    However..
    You can always take a look as an example for the teleporter if thats the case at something like ticket.inc, it stores cords + the world itself and i am not aware of anyone exploiting it. In v19+ they also added PaidWorldSet.txt which is essentially a re-worked version of ticket.inc to. You can always check the newest 21.2 and see how that works. It's generally safe, as long as it's server sided.

  3. #3
    Enthusiast Int16 is online now
    MemberRank
    Oct 2022 Join Date
    33Posts
    Thanks i'll give it a try

  4. #4
    RE:ℓσα∂є∂ Fenris is offline
    MemberRank
    Sep 2011 Join Date
    RE:ℓσα∂Location
    588Posts
    All the "resource" is, is a list of files that are loaded on the client and on some of the applications to load in dynamic data. This allows people to learn some basic formats and add items, etc without having access to hardcoding the information. It also helps with packaging different files for different servers.


    The safeness -- well, it all depends on how you're using and interpreting the data of the resource. As Ketchup stated, "generally safe if server-sided".

    If you're sending the 3d-coordinates for the teleports position from the client to the World Server, then you can have issues. But, if the World Server loads a copy of the file from the resource directory, then you'll be fine if you're using data from that file on the World Server. I can get in to more issues that could arise, but, they're more related to other issues instead of resource.


    Hardcoding is always going to be faster, as you wouldn't need to initialize hard-disk i/o on another file and stream the files for the information required. You could create an asynchronous loader to help resolve some of the slowness of using more resource files or higher quality textures.

    Besides updating to an asynchronous loader, I would also suggest the following: Because, you have to reboot World Server to try changes to resource, I think creating a Reload File command would be good. Ideally, a background patcher would also request the client to reload background patches.

  5. #5
    Enthusiast Int16 is online now
    MemberRank
    Oct 2022 Join Date
    33Posts
    so ive made a .inc file that passes all the info into a struct and saves it all in a struct array

    Code:
    #ifdef __SYS_TELE16
    struct TeleportData
    {
        int         nIndex;
        TCHAR       szName[64];
        TCHAR       szDesc[256];
        D3DXVECTOR3 vPos;
        int         nMinLevel;
        int         nMaxLevel;
        DWORD       dwCoolTime;
        DWORD       dwMonsterId;
    };
    #endif //__SYS_TELE16
    
    in wndfield i pass the struct itself through the packet

    Code:
        else if( nID == WIDC_BUTTON )
        {
            g_DPlay.SendTeleport(*prj.m_aTeleportInfo.GetAt(m_nCursorIndex));
            Destroy();
        }
        return CWndNeuz::OnChildNotify(message,nID,pLResult);
    
    Code:
    void CDPClient::SendTeleport(TeleportData tpData)
    {
        BEFORESENDSOLE(ar, PACKETTYPE_TELE16, DPID_UNKNOWN);
        ar << tpData;
        SEND(ar, this, DPID_SERVERPLAYER);
    }
    #endif  //__SYS_TELE16
    
    and here is the dpsvr :

    Code:
    #ifdef __SYS_TELE16
    void CDPSrvr::OnTeleport(CAr & ar, DPID dpidCache, DPID dpidUser, LPBYTE, u_long)
    {
        CUser* pUser = g_UserMng.GetUser(dpidCache, dpidUser);
        TeleportData TPData;
        ar >> TPData;
        CWorld* pWorld;
        
        if (IsValidObj(pUser) && (pWorld = pUser->GetWorld()))
        {
            if (pUser->IsDie() || pUser->IsCollecting() || pUser->m_vtInfo.VendorIsVendor() || pUser->m_vtInfo.IsVendorOpen())
                return;
    
            if (!pUser->IsAuthHigher(AUTH_GAMEMASTER))
            {   
                if(pUser->IsAttackMode() || pUser->GetWorld() && pUser->GetWorld()->GetID() == WI_WORLD_GUILDWAR)
                {
                    pUser->AddText("Can't teleport while fighting.");
                    return;
                }
            }
            pUser->REPLACE(g_uIdofMulti, 1, TPData.vPos, REPLACE_NORMAL, nDefaultLayer);//<---
        }
    }
    #endif //__SYS_TELE16
    
    now you can see where im at and my only concern :
    should i send the struct directly through the packet like i did or.. should i send the listbox selected index and cast the struct in dpsvr ?

    i might overthinking something

    thanks in advance

  6. #6
    RE:ℓσα∂є∂ Fenris is offline
    MemberRank
    Sep 2011 Join Date
    RE:ℓσα∂Location
    588Posts
    When you pass the struct in to a packet, you're sending the entire data of said struct from a single client to the server, so You're sending 352 bytes to the server each time someone is requesting to teleport.

    In the scenario you posted, you fully trust the user's client because you send their version of the read data. it could be manipulated. They could have edited the file, or bypassed memory editing detection, etc, and if you start checking member variables of the variable Tpdata in worldserver, you're checking that users' clients data.

    So... that brings us to:
    What information is needed, where is that information needed? Also, what information requires proper validation? How should you validate the information?

    As your question states,
    "should i send the listbox selected index and cast the struct in dpsvr ?"

    Yes.
    Sending the listbox index would send 4 bytes to the server. Those 4 bytes can be validated on the server as you would check to see if the index is contained in the container. You'd be able to then access the required information like "World id", "Position" from a verified source (locally).

    Because the structs dont need to be the same, I would only define what is required on the client to the client and same with the server. You don't need name, or description to be stored on the worldserver, you can skip the token rather storing it.

  7. #7
    Enthusiast Int16 is online now
    MemberRank
    Oct 2022 Join Date
    33Posts
    ahhhhh ok i get it now so basically i leave the inc file how it is but create 2 different structs (or 2 different types of information gathering)
    where one is client sided and the other one is server sided

    client sided: (reading the .inc file by the clients resource)
    Code:
    struct TeleportData
    {
        TCHAR       szName[64];
        TCHAR       szDesc[256];
        int         nMinLevel;
        int         nMaxLevel;
        DWORD       dwCoolTime;
        DWORD       dwMonsterId; //drop log
    };
    server sided : (reading the .inc file server sided )

    Code:
    struct TeleportDataWorld
    {
        D3DXVECTOR3 vPos;
        DWORD dwWorldID;
    };
    and then i use the listbox index packet variable to cycle through the information
    Last edited by Int16; 2 Weeks Ago at 09:33 AM.

  8. #8
    RE:ℓσα∂є∂ Fenris is offline
    MemberRank
    Sep 2011 Join Date
    RE:ℓσα∂Location
    588Posts
    I explain development as just balancing different software engineering principles and ideas.


    project.h
    Code:
    struct TeleportInfo
    {
    #if defined(__WORLDSERVER)
         unsigned long dwWorldID;
         D3DXVECTOR3 vPos;
    #elif defined(__CLIENT)
        TCHAR szName[64];
        TCHAR szDesc[256];
        unsigned long coolDown;
    
        struct MobInfo
        {
            using List = std::vector<unsigned long>;
            int minLevel;
            int maxLevel;
            List Mobs;
        } mInfo;
    #endif
    };
    So, I changed a few things. When working with structs, you have to understand what memory alignment is and how structures are padded. It's not required, it's just if you want to optimize some memory foot printing especially for POD (plain old data). When compiling on x86, the compiler will want to optimize memory alignment to 4 bytes for faster memory access, so it will pad structures.


    project.h
    Code:
    using TeleportData = std::vector<TeleportInfo>;
    TeleportData TPData;
    void LoadTeleporterData();

    project.cpp
    Code:
    void CProject::LoadTeleporterData()
    {
        CScript s;
        if (!s.Load("TeleporterData.inc"))
            return false;
    
         s.GetToken();
        while (s.tok != FINISHED)
        {
             TeleportInfo tpInf{};
    #ifdef __WORLDSERVER
             tpInf.dwWorldId = atoi(s.token);
             tpInf.vPos.x = s.GetFloat();
             tpInf.vPos.y= s.GetFloat();
             tpInf.vPos.z = s.GetFloat();
             s.GetToken();
             s.GetToken();
             s.GetNumber();
             s.GetNumber();
             s.GetNumber();
             s.GetToken();
             if (s.Token == "{")
             {
                   while (s.Token != "}")
                       s.GetNumber();
                   s.GetToken();
             }
    #else
             s.GetFloat();
             s.GetFloat();
             s.GetFloat();
             s.GetToken();
             _tcsncpy(tpInf.szName, s.token, sizeof(tpInf.szName) / sizeof(tpInf.szName[0]) -2);
    	tpInf.szName[sizeof(tpInf.szName) / sizeof(tpInf.szName[0]) - 1] = '\0';
    
             _tcsncpy(tpInf.szDesc, s.token, sizeof(tpInf.szDesc) / sizeof(tpInf.szDesc[0]) -2);
    	tpInf.szDesc[sizeof(tpInf.szDesc) / sizeof(tpInf.szDesc[0]) - 1] = '\0';
    
            tpInf.coolDown = s.GetNumber();
            tpInf.mInfo.minLevel = s.GetNumber();
            tpInf.mInfo.maxLevel = s.GetNumber();
            s.GetToken();
             if (s.Token == "{")
             {
                   unsigned long mobid = s.GetNumber();
                   while (s.Token != "}")
                       tpInfo.mInfo.Mobs.emplace_back(mobid);
                       mobid = s.GetNumber();
                   s.GetToken();
             }
            TPData.emplace_back(std::move(tpInf));
        }
    }
    You could separate the resource files which would save the extra "get" calls that aren't stored, but then you need to keep track of both files being in the same order. Not only that, but if you do that for like a system extension on... let's say item prop... where it's still on every item, then it'd be a bad idea due to the fact you're opening another stream for the same amount of information that can be acquired from one stream.

    You're able to keep it as one file by just calling the 'Get' functions, as shown here. Now, something that is a little 'overboard' nowadays, is that you can change it to stream over the data completely rather than storing the read token within the scanner.

    If the vectors are read as such and not sorted, then they should match the client. you'd be able to send the selected cursor to the world server.

    // cdpsrvr
    Code:
    void CDPSrvr::OnTeleport(CAr & ar, DPID dpidCache, DPID dpidUser, LPBYTE, u_long)
    {
        unsigned int selection;
        ar >> selection;
    
        if (selection >= prj.TPData.size()) 
            return false;
    
        CUser* pUser = g_UserMng.GetUser(dpidCache, dpidUser);
        if (IsValidObj(pUser))
        {
            if (pUser->IsDie() || pUser->IsCollecting() || pUser->m_vtInfo.VendorIsVendor() || pUser->m_vtInfo.IsVendorOpen())
                return;
    
           const TeleportInfo& inf = TPData[selection];
            if (!pUser->IsAuthHigher(AUTH_GAMEMASTER))
            {   
                if(pUser->IsAttackMode() || pUser->GetWorld() && pUser->GetWorld()->GetID() == WI_WORLD_GUILDWAR)
                {
                    pUser->AddText("Can't teleport while fighting.");
                    return;
                }
            }
    
            // You could also add like gold requirment, or actual level requirment to tp. There's been a tp system
            // that you had to learn locations to tp to, that's another thing thats possible.
    
            pUser->REPLACE(g_uIdofMulti, inf.dwWorldId, inf.vPos, REPLACE_NORMAL, nDefaultLayer);//<---
        }
    }

  9. #9
    Enthusiast Int16 is online now
    MemberRank
    Oct 2022 Join Date
    33Posts
    thank you i understand it now :)

  10. #10
    Enthusiast Int16 is online now
    MemberRank
    Oct 2022 Join Date
    33Posts
    EDIT : [FIXED] ohh nevemind the descriptions are too long i had to increase the tchar size ooops


    i know this might not be the topic right now but ill decided to do a .txt.txt to pre define the text for the teleporter

    teleport16.inc
    Code:
    //dwWorldID       x      y     z      szName               szDesc
    WI_WORLD_MADRIGAL 6975.4 100.0 3342.9 IDS_TELEPORT_TXT_001 IDS_TELEPORT_TXT_002
    WI_WORLD_MADRIGAL 8315.0 100.0 3724.0 IDS_TELEPORT_TXT_003 IDS_TELEPORT_TXT_004
    WI_WORLD_MADRIGAL 3808.0 59.0  4455.0 IDS_TELEPORT_TXT_005 IDS_TELEPORT_TXT_006
    
    teleport16.txt.txt
    Code:
    IDS_TELEPORT_TXT_000
    IDS_TELEPORT_TXT_001        Flaris
    IDS_TELEPORT_TXT_002        Flaris is the continent where vagrants start. The strongest Masquerpets that normally appear on this continent are Bangs, which range from level 19 to 23. The town on this continent is named Flarine. This town has small houses and vendors selling low-level items.
    IDS_TELEPORT_TXT_003        Saint Morning
    IDS_TELEPORT_TXT_004        Saint Morning is home to many mobs. Those mobs range from level 19-43. There National Motto is "May Rhisis guide your travels" and there National Antem is "Hymn to the Heavens".
    IDS_TELEPORT_TXT_005        Darkon 2 ( City )
    IDS_TELEPORT_TXT_006        In Darkon 2 you will find the city of Darkon, often called Darkon-City, which is often incorrectly referred to as the capital because that is where the high-level characters reside.
    IDS_TELEPORT_TXT_007
    
    inside "void CProject::LoadStrings()" i added
    Code:
    #ifdef __SYS_TELE16
            ,"teleport16.txt.txt"
    #endif //__SYS_TELE16
    
    soo the neuz crashes instantly without any errors
    but i doubt it has something to do with my scanner beacuse i can use for example propItem defined text and put it in my .inc file and it would work fine

    Code:
    //dwWorldID       x      y     z      szName                      szDesc
    WI_WORLD_MADRIGAL 6975.4 100.0 3342.9 IDS_PROPITEM_TXT_000016  IDS_PROPITEM_TXT_000020
    



    is there more then adding it to loadStrings() ?
    and yeah i also merged both files
    Last edited by Int16; 2 Weeks Ago at 04:01 AM. Reason: fixed it



Advertisement