REQUEST: Port Half-Life SDK Extension DLLs CLEANLY to Windows CE

Discussion in 'Sega Dreamcast Development and Research' started by TerdFerguson, Dec 3, 2016.

  1. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    Making this thread because my other Half-Life thread is mostly derailed/general HLDC modding thread now. But it's probably the best documentation of GoldSRC:Dreamcast on the internet, though unorganized
    http://assemblergames.com/l/threads...some-functional-multiplayer-components.57318/

    I'm going to try to keep this short and to the point and try to evade reiterating things said many times throughout the other thread
    --------------------------------------------------------------------

    Requesting that someone with the time and ability cleanly port Half-Life SDK engine extension DLLs (hl.dll/game.dll and client.dll) *cleanly* to Windows CE and *cleanly* compile it with the Windows CE SDK for Dreamcast

    These DLLs add all of the new functions and features for each Half-Life mod. For example, the 'buy' menu in Counter-Strike, or class selection in Team Fortress Classic. The scope of exapandability for these DLLs seems to be near limitless, see this video for example


    With extensive research of console commands, and examination of HLDC's binary disassembly, it looks like the ability for the loading of these extensions is plausible. But remains untested because the full HLSDK has never been ported to Windows CE cleanly

    A user "Moi" from dcemulation.org ported the source for "hl.dll", only one of the two DLLs, many years ago which I have the source code for. But he said he used many hacks to simply get it to compile. He said it didn't work, but only tried one method and not the console command to load a mod which I'll explain in a minute

    I obtained this source code from "Rambo" on TheISOZone, and someone named "Tasos" in the DC-scene compiled it, but he too used many hacks to get it to link correctly

    This is not resolute for the following reasons:
    • The port had many hacks to begin with
    • The compile of hl.dll that I tested also had many more hacks and hacks during linking, where Tasos couldn't send me the source to extract and compile on my machine without errors
    Another reason is because there are no references to "hl.dll" in the binary. But there are references to "client.dll". It's possible it needs client.dll to be loaded, then client.dll tells the engine to load it's game.dll (hl.dll / tfc.dll / etc )

    The Half-Life console command on PC for loading a new mod is "gamedir"
    So for example, to start counter-strike you'd type "gamedir cstrike"

    In the pre-steam version of Half-Life (Which was the version ported to Dreamcast), this will load client.dll and game.dll for counter-strike, as well as loading all the new configuration files and menu images for the mod

    On Dreamcast, the equivilent to "gamedir" is "startgame"
    So on Dreamcast, if you type "startgame cstrike", it will load the menu images, I think langtags.txt (menu text), and change the HUD images to Counter-Strike HUD

    My point is, if the equivalent command for "gamedir" behaves identically to the Dreamcast command, it may also load the HLSDK mod extensions
    (see second post for evidence of this, as this post would be too long with it here)

    To test this, we need both "client.dll" and "hl.dll" ported and compiled cleanly to Windows CE. With some minor but noticeable modification to know it did load, like HUD color or a new console command that will echo text to console
    ----------------------------------------------

    The reason why this should be done:
    • As shown in the video above, GoldSRC can almost be infinitely expanded. Allowing new, full "AAA" quality games to be developed for Dreamcast on GoldSRC
    • Support for multiplayer and networking can be added
    • Every open source mod can be ported to Dreamcast as long as it will run with hardware limitations
    • Misc hardware support can be added like microphone
    • BBA support can be added
    • PC/DC cross compatible online play would be possible if the PC mod was modified and recompiled to use the same newly implemented networking as the Dreamcast version
    • Implement downloading of gameserver resources (server sounds, etc, "M-M-M-MONSTERKILL") to serial SD card adapter
    • ETC
    If there is no native way to load the extensions, by console command or command line options (which there are references to command line options in the binary which i'll quote in second post), then the extensions can perhaps be injected into memory at runtime using create_remote_thread or something. Since the Half-Life SDK (open source) is from the same codebase as the Half-Life engine binary (closed source on both Dreamcast and PC)

    So to summarize what I'm requesting:
    • Find the most suitable version of the Half-Life SDK to port (Newer versions might not work with the pre-steam version of Half-Life, which is the version ported to Dreamcast and they're almost identical 1:1)
    • Cleanly port the entire Half-Life SDK to Windows CE/SH4/Dreamcast
    • Make a small but noticable modification like HUD color change or console command that prints text to know the extensions have loaded
    • Compile both client.dll and hl.dll, distribute for others to test
    • Put the clean, compile ready source code on GitHub as Half-Life Dreamcast SDK, without changes to know extensions have loaded
    • After port, compile, test, if there is no native way to load, begin development of an injector applet that will force-load the user specified mod at runtime (multiple mods can be on one disc)
    I'm not requesting someone implement the new features listed above, I simply want to test the loading of extensions after a clean port and compile. I have a large hunch after all my research on my other thread that there is a way it will. If the concept is proven it's up to others if they want to implement all of the new stuff

    I'm probably forgetting many details, but they're likely in the other thread. I hope there is someone interested in this that can help. If you're interested, download the hldc-sdk I started a few months ago to get started. Moi's hacked/seemingly-messy port source code is in there for reference

    (I hope this is the right one, one of them is corrupt I forget)
    http://hldc.dreampipe.net/sdk/hldc-sdk-0.0.7.zip
     
    Anthony817 and truemaster1 like this.
  2. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    Citations:

    Compiler reference to engine DLL initilization, also in the same area of the binary strings as startgame, adding to plausibility
    References to command line parameters in the binary
    References to client.dll in binary disassembly
    http://assemblergames.com/l/threads...tiplayer-components.57318/page-16#post-877329

    References to command line options in binary disassembly
    http://assemblergames.com/l/threads...tiplayer-components.57318/page-17#post-880214

    Startgame loading HUD assets from a mod (counter-strike)
    http://assemblergames.com/l/threads...tiplayer-components.57318/page-10#post-861077

    Liblist.gam (resource list for loading mod assets on PC, specifies expansion DLL) from original HLDC leak in the Blue-Shift folder
    References to client.dll in binary strings
    [​IMG]
     
    Last edited: Dec 3, 2016
    Anthony817 and truemaster1 like this.
  3. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    Alright, so it looks like I FINALLY compiled a client.dll. I just started a new "Dreamcast Application" project in VC++ 6.0, added each source file one by one, and there was only a few things I had to do. The same thing Moi had to do for his compile

    So there really wasn't much to "port", which is kind of ironic. It took me a half hour to figure the above out

    Doing some testing now, doesn't look like there's any effect. But I'm not done testing, and command line parameters can possibly be tested by someone I know

    Assuming this can't load natively, there's this in cdll_int.cpp:
    Code:
    /*
    ==========================
        Initialize
    
    Called when the DLL is first loaded.
    ==========================
    */
    extern "C"
    {
    int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion );
    int DLLEXPORT HUD_VidInit( void );
    int DLLEXPORT HUD_Init( void );
    int DLLEXPORT HUD_Redraw( float flTime, int intermission );
    int DLLEXPORT HUD_UpdateClientData( client_data_t *cdata, float flTime );
    int DLLEXPORT HUD_Reset ( void );
    }
    
    
    int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion )
    {
        gEngfuncs = *pEnginefuncs;
    
        //!!! mwh UNDONE We need to think about our versioning strategy. Do we want to try to be compatible
        // with previous versions, especially when we're only 'bonus' functionality? Should it be the engine
        // that decides if the DLL is compliant?
    
        if (iVersion != CLDLL_INTERFACE_VERSION)
            return 0;
    
        memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t));
    
        return 1;
    }
    
    
    If someone can make one single assembly hack or something to call "Initialize", that might be the only entry point needed
    @SiZiOUS

    Attached the compiled client.dll, and I'll create a compile ready .zip of the client.dll source code, then "port" game.dll and do the same thing
     

    Attached Files:

  4. megavolt85

    megavolt85 Peppy Member

    Joined:
    Jan 8, 2015
    Messages:
    332
    Likes Received:
    483
    Code:
    int stricmp(const char *a, const char *b)
    {
        const char *s1 = a, *s2 = b;
      
        while (toupper(*s1) == toupper(*s2))
        {
            if (*s1 == 0)
                return 0;
            s1++;
            s2++;
        }
      
        return toupper(*(unsigned const char *)s1) - toupper(*(unsigned const char *)(s2));
    }
    
     
    TerdFerguson likes this.
  5. rso

    rso °

    Joined:
    Mar 26, 2010
    Messages:
    2,207
    Likes Received:
    472
    yep, replacing standard library function calls with similar-sounding ones that work differently can have "interesting" results. better to shoehorn in some small replacements for those.
    Code:
    void *calloc(size_t nmemb, size_t size) {
        void *mem = malloc(nmemb * size);
        return mem ? memset(mem, 0, nmemb * size) : NULL;
    }
    stricmp may be already available as _stricmp.
     
    TerdFerguson likes this.
  6. Trident6

    Trident6 Spirited Member

    Joined:
    Oct 17, 2015
    Messages:
    119
    Likes Received:
    55
    Yeah replacing calloc with malloc isn't a great idea, since calloc initializes the new memory to zero and malloc doesn't. You might get lucky depending on what happens with the memory afterword but you should either write a replacement function (above) or find the correct header for calloc.
     
    TerdFerguson likes this.
  7. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    I had to replace stricmp with strcmp. Calloc didn't give me any issues. There's also 47 compiler warnings, so I'd imagine this wasn't a proper test
     
  8. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    Is that a replacement for the function?

    Edit: Mods, my bad for double post

    @Trident6 @megavolt85 @rso I'll start over later and use those re-implementations of those functions, and compile both client.dll and hl.dll. But I can also create a .zip of the source tree for both extensions that are ready to open in Windows CE Dreamcast SDK if you guys are interested in creating a "perfect port"

    A good way would be getting it to compile for Dreamcast, then compile it for Win32 (my current version can do this by using the Win32 time.h library instead of Moi's re-implementation for WCE), then getting Win32 Half-Life to load the dlls

    Even if it cannot load, we'll still have the HLSDK ported to Dreamcast finally, and it'd be open sourced for others to try this. Considering we might just need to call the Initialize() function from cdll_int.cpp in some sort of function hook or assembly hack of that nature

    In the second post in this thread, you guys can see there's eng_cdll_int.cpp. So we know the engine side code for initializing the cdll is there in one form or another. If any of you are good with Hex Rays/IDA Pro I have the ASM for the HLDC binary, if you guys want to poke around near the references to eng_cdll_int.cpp and see if you can find if the initialize function was changed or renamed
     
    Last edited: Dec 14, 2016
  9. megavolt85

    megavolt85 Peppy Member

    Joined:
    Jan 8, 2015
    Messages:
    332
    Likes Received:
    483
    yes
    stricmp("Hello", "hello")
    result = 0

    strcmp("Hello", "hello")
    result != 0
    ;)

    show warnings
     
  10. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    For stricmp there's two files that call it, scoreboard.cpp and status_icons.cpp, using your replacement twice gave me a linker error (stricmp already defined in scoreboard.obj), so in status_icons.cpp I had to do this
    Code:
    namespace
    {
        int stricmp(const char *a, const char *b)
    {
        const char *s1 = a, *s2 = b;
     
        while (toupper(*s1) == toupper(*s2))
        {
            if (*s1 == 0)
                return 0;
            s1++;
            s2++;
        }
     
        return toupper(*(unsigned const char *)s1) - toupper(*(unsigned const char *)(s2));
    }
    }
    And it compiled

    Here are warnings
    warning1.png

    warning2.png
    All the same warnings, might be something simple. Going to do this for hl.dll now

    Edit: This is what it complains about, one example but there's many different cases
    warning3.png
     
  11. megavolt85

    megavolt85 Peppy Member

    Joined:
    Jan 8, 2015
    Messages:
    332
    Likes Received:
    483
    place my code to scoreboard.cpp
    in status_icons.cpp place
    Code:
    extern int stricmp(const char *a, const char *b);
    
    upload message.cpp
     
  12. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    Did that and it compiles fine

    Here is message.cpp

    I'm going through hl.dll tree now and taking notes of errors, almost halfway through
    Just went through hl.dll source tree, there's only a few files with errors, and a lot of them you guys already helped figure out or Moi figured out the time.h stuff

    Here is what needs to be fixed
    If you guys could also help with those few other undeclared identifiers and that one C2664 error (it gives that error more than once though in nodes.cpp but I imagine you only have to apply the same fix to each)

    Thanks for the help thus far guys, I'll test the new client.dll in a few hours
     

    Attached Files:

    Last edited: Dec 14, 2016
  13. megavolt85

    megavolt85 Peppy Member

    Joined:
    Jan 8, 2015
    Messages:
    332
    Likes Received:
    483
    message.cpp line 99
    xPos = (1.0 + x) * ScreenWidth - totalWidth; // Alight right
    xPos is int
    x is float
    then
    xPos = (int)(1.0 + x) * ScreenWidth - totalWidth; // Alight right
     
    TerdFerguson likes this.
  14. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    So just replace line 99 with
    Code:
    xPos = (int)(1.0 + x) * ScreenWidth - totalWidth; // Alight right
    ?

    Edit: Did that and there wasn't any effect, I still get the warning on line 99 and the rest of the warnings
     
  15. megavolt85

    megavolt85 Peppy Member

    Joined:
    Jan 8, 2015
    Messages:
    332
    Likes Received:
    483
    yes

    Code:
    int isspace(int character)
    {
        switch (character)
        {
            case ' ':
            case '\t':   
            case '\n':
            case '\v':
            case '\f':
            case '\r':
                return 1;
                break;
            default:
                break;
        }
       
        return 0;
    }
    
     
    TerdFerguson likes this.
  16. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    Done, and added your function into all of the files that gave the undeclared isspace error. But the linker will probably complain about the redefinition like stricmp did

    Edit: Updated error list
    Edit2: Can't I create a header file that will take care of all the 'stricmp' errors without declaring something in each individual source file?
     
  17. megavolt85

    megavolt85 Peppy Member

    Joined:
    Jan 8, 2015
    Messages:
    332
    Likes Received:
    483
    upload Makefile
     
  18. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    Attached both client.dll makefile since that's done except for warnings and hl.dll makefile

    Edit: do you want the Release makefiles instead? I think client was release and hl was debug
    I see they're both combined in one
     

    Attached Files:

    Last edited: Dec 14, 2016
  19. megavolt85

    megavolt85 Peppy Member

    Joined:
    Jan 8, 2015
    Messages:
    332
    Likes Received:
    483
    place to util.cpp
    Code:
    int stricmp(const char *a, const char *b)
    {
       const char *s1 = a, *s2 = b;
     
       while (toupper(*s1) == toupper(*s2))
       {
           if (*s1 == 0)
               return 0;
           s1++;
           s2++;
       }
     
       return toupper(*(unsigned const char *)s1) - toupper(*(unsigned const char *)(s2));
    }
    
    int isspace(int character)
    {
       switch (character)
       {
           case ' ':
           case '\t':   
           case '\n':
           case '\v':
           case '\f':
           case '\r':
               return 1;
               break;
           default:
               break;
       }
       
       return 0;
    }
    
    void *calloc(size_t nmemb, size_t size) 
    {
       void *mem = malloc(nmemb * size);
       return mem ? memset(mem, 0, nmemb * size) : NULL;
    }
    
    create helper.h

    Code:
    extern int stricmp(const char *a, const char *b);
    extern int isspace(int character);
    extern void *calloc(size_t nmemb, size_t size);
    
    add to all files with stricmp undeclared or isspace undeclared or calloc undeclared

    Code:
    #include "helper.h"
    
     
    TerdFerguson likes this.
  20. TerdFerguson

    TerdFerguson ls ~/

    Joined:
    Apr 27, 2015
    Messages:
    755
    Likes Received:
    468
    Did all of that, updated error list
    Here is Moi's Time.h replacement
    Code:
    // Time.h replacement by Moi
    struct timeb {
        time_t time;
        unsigned short millitm;
    };
    
    static void ftime( struct timeb *tb )
    {
        SYSTEMTIME  st;
        int days, years, leapyears;
    
        if(tb == NULL)
        {
           // nlSetError(NL_NULL_POINTER);
            return;
        }
        GetSystemTime(&st);
        leapyears = (st.wYear - 1970 + 1) / 4;
        years = st.wYear - 1970 - leapyears;
    
        days = years * 365 + leapyears * 366;
    
        switch (st.wMonth) {
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:
            days += 31;
            break;
        case 4:
        case 6:
        case 9:
        case 11:
            days += 30;
            break;
        case 2:
            days += (st.wYear%4 == 0) ? 29 : 28;
            break;
        default:
            break;
        }
        days += st.wDay;
        tb->time = days * 86400 + st.wHour * 3600 + st.wMinute * 60 + st.wSecond;
        tb->millitm = st.wMilliseconds;
    }
    
    time_t time(time_t *t)
    {
        struct timeb tb;
    
        ftime(&tb);
        *t = tb.time;
    
        return *t;
    }
    // End Time.h replacemen
    So we're down to 12 errors, half of those are this from nodes.cpp
    Here is the code for CreateDirectory, probably a Windows32 API function that isn't supported in Windows CE (maybe a subset of it does)
    Code:
    // make sure directories have been made
        GET_GAME_DIR( szNrpFilename );
        strcat( szNrpFilename, "/maps" );
        CreateDirectory( szNrpFilename, NULL );
        strcat( szNrpFilename, "/graphs" );
        CreateDirectory( szNrpFilename, NULL );
    
        strcat( szNrpFilename, "/" );
        strcat( szNrpFilename, STRING( gpGlobals->mapname ) );
        strcat( szNrpFilename, ".nrp" );
    
        file = fopen ( szNrpFilename, "w+" );
    
    Code:
    // make sure the directories have been made
        char    szDirName[MAX_PATH];
        GET_GAME_DIR( szDirName );
        strcat( szDirName, "/maps" );
        CreateDirectory( szDirName, NULL );
        strcat( szDirName, "/graphs" );
        CreateDirectory( szDirName, NULL );
    
        strcpy ( szFilename, "maps/graphs/" );
        strcat ( szFilename, szMapName );
        strcat( szFilename, ".nod" );
    
        pMemFile = aMemFile = LOAD_FILE_FOR_ME(szFilename, &length);
    
    Code:
    // make sure directories have been made
        GET_GAME_DIR( szFilename );
        strcat( szFilename, "/maps" );
        CreateDirectory( szFilename, NULL );
        strcat( szFilename, "/graphs" );
        CreateDirectory( szFilename, NULL );
    
        strcat( szFilename, "/" );
        strcat( szFilename, szMapName );
        strcat( szFilename, ".nod" );
    
        file = fopen ( szFilename, "wb" );
    
        ALERT ( at_aiconsole, "Created: %s\n", szFilename );
    Edit: Attached nodes.cpp and nodes.h
     

    Attached Files:

    Last edited: Dec 14, 2016

Share This Page