<commit_before>/* 
 * Standard Streamer Plugin for Mod Loader
 * Copyright (C) 2013-2014  LINK/2012 <<EMAIL>>
 * Licensed under the MIT License, see LICENSE at top level directory.
 * 
 */
#include <stdinc.hpp>
#include "streaming.hpp"
using namespace modloader;

extern "C"
{
    // Assembly hooks at "asm/" folder
    extern void HOOK_RegisterNextModelRead();
    extern void HOOK_NewFile();
    extern void HOOK_FixBikeSuspLines();

    // Next model read registers. It's important to have those two vars! Don't leave only one!
    int  iNextModelBeingLoaded = -1;            // Set by RegisterNextModelRead, will then be sent to iModelBeingLoaded
    int  iModelBeingLoaded = -1;                // Model currently passing throught CdStreamRead

    //
    CStreamingInfo* ms_aInfoForModel = injector::ReadMemory<CStreamingInfo*>(0x5B8AE8, true);
    DWORD *pStreamCreateFlags        = memory_pointer(0x8E3FE0).get();

    // Returns the file handle to be used for iModelBeingLoaded (called from Assembly)
    HANDLE CallGetAbstractHandle(HANDLE hFile)
    {
        if(iModelBeingLoaded == -1) return hFile;
        return streaming.TryOpenAbstractHandle(iModelBeingLoaded, hFile);
    }

    // Registers the next model to be loaded (called from Assembly)
    void RegisterNextModelRead(int id)
    {
        iNextModelBeingLoaded = id;
        if(streaming.DoesModelNeedsFallback(id))    // <- make sure the resource hasn't been deleted from disk
        {
            plugin_ptr->Log("Resource id %d has been deleted from disk, falling back to stock model.", id);
            streaming.FallbackResource(id, true);   // forceful but safe since we are before info setup in RequestModelStream
        }
    }

    static HANDLE __stdcall CreateFileForCdStream(
        LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
        LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
        DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
    {
        LPCSTR lpActualFileName = streaming.GetCdStreamPath(lpFileName);
        plugin_ptr->Log("Opening file for streaming \"%s\"", lpActualFileName);
        return CreateFileA(
            lpActualFileName, dwDesiredAccess, dwShareMode,
            lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
    }

    
    // Reproduces the code @6BF741
    void FixBikeSuspPtr(char* m_pColData)
    {
        *(char*)(m_pColData + 6) = 4;
        char* ptr = injector::cstd<char*(size_t)>::call<0x72F420>(128); // CMemoryMgr::Malloc
        *(char**)(m_pColData + 16) = ptr;
        *(uint32_t*)(ptr + 10) = 0x47C34FFFu;   // a float actually
        *(uint32_t*)(ptr + 8)  = 0x47C34FFFu;   // a float actually
    }
};



/*
 *  Streaming thread
 *      This thread reads pieces from cd images and in mod loader on disk files
 */
int __stdcall CdStreamThread()
{
    DWORD nBytesReaden;
    
    // Get reference to the addresses we'll use
    CdStreamInfo& cdinfo = *memory_pointer(0x8E3FEC).get<CdStreamInfo>();
    
    // Loop in search of things to load in the queue
    while(true)
    {
        int i = -1;
        CdStream* cd;
        bool bIsAbstract = false;
        CAbstractStreaming::AbctFileHandle* sfile = nullptr;
        
        // Wait until there's something to be loaded...
        WaitForSingleObject(cdinfo.semaphore, -1);
        
        // Take the stream index from the queue
        i = GetFirstInQueue(&cdinfo.queue);
        if(i == -1) continue;
        
        cd = &cdinfo.pStreams[i];
        cd->bInUse = true;          // Mark the stream as under work
        if(cd->status == 0)
        {
            // Setup vars
            size_t bsize  = cd->nSectorsToRead;
            size_t offset = cd->nSectorOffset  << 11;       // translate 2KiB based offset to actual offset
            size_t size   = bsize << 11;                    // translate 2KiB based size to actual size
            HANDLE hFile  = (HANDLE) cd->hFile;
            bool bResult  = false;
            const char* filename = nullptr; int index = -1; // When abstract those fields are valid
            
            // Try to find abstract file from hFile
            if(true)
            {
                scoped_lock xlock(streaming.cs);
                auto it = std::find(streaming.stm_files.begin(), streaming.stm_files.end(), hFile);
                if(it != streaming.stm_files.end())
                {
                    bIsAbstract = true;
                    
                    // Setup vars based on abstract file
                    sfile  = &(*it);
                    offset = 0;
                    size   = (size_t) sfile->info.file->size;
                    bsize  = GetSizeInBlocks(size);
                    index  = sfile->index;
                    filename = sfile->info.file->filepath();
                }
            }
            
            
            // Setup overlapped structure
            cd->overlapped.Offset     = offset;
            cd->overlapped.OffsetHigh = 0;
            
            // Read the stream
            if(ReadFile(hFile, cd->lpBuffer, size, &nBytesReaden, &cd->overlapped))
            {
                bResult = true;
            }
            else
            {
                if(GetLastError() == ERROR_IO_PENDING)
                {
                    // This happens when the stream was open for async operations, let's wait until everything has been read
                    // As noted on MSDN [http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx], when
                    // you open a stream with FILE_FLAG_NO_BUFFERING  (R* does that with their cd streams) it gives you maximum
                    // performance if you use overlapped I/O
                    bResult = GetOverlappedResult(hFile, &cd->overlapped, &nBytesReaden, true) != 0;
                }<commit_msg>Closes #32<commit_after>/* 
 * Standard Streamer Plugin for Mod Loader
 * Copyright (C) 2013-2014  LINK/2012 <dma_20<EMAIL>>
 * Licensed under the MIT License, see LICENSE at top level directory.
 * 
 */
#include <stdinc.hpp>
#include "streaming.hpp"
using namespace modloader;

extern "C"
{
    // Assembly hooks at "asm/" folder
    extern void HOOK_RegisterNextModelRead();
    extern void HOOK_NewFile();
    extern void HOOK_FixBikeSuspLines();

    // Next model read registers. It's important to have those two vars! Don't leave only one!
    int  iNextModelBeingLoaded = -1;            // Set by RegisterNextModelRead, will then be sent to iModelBeingLoaded
    int  iModelBeingLoaded = -1;                // Model currently passing throught CdStreamRead

    //
    CStreamingInfo* ms_aInfoForModel = injector::ReadMemory<CStreamingInfo*>(0x5B8AE8, true);
    DWORD *pStreamCreateFlags        = memory_pointer(0x8E3FE0).get();

    // Returns the file handle to be used for iModelBeingLoaded (called from Assembly)
    HANDLE CallGetAbstractHandle(HANDLE hFile)
    {
        if(iModelBeingLoaded == -1) return hFile;
        return streaming.TryOpenAbstractHandle(iModelBeingLoaded, hFile);
    }

    // Registers the next model to be loaded (called from Assembly)
    void RegisterNextModelRead(int id)
    {
        iNextModelBeingLoaded = id;
        if(streaming.DoesModelNeedsFallback(id))    // <- make sure the resource hasn't been deleted from disk
        {
            plugin_ptr->Log("Resource id %d has been deleted from disk, falling back to stock model.", id);
            streaming.FallbackResource(id, true);   // forceful but safe since we are before info setup in RequestModelStream
        }
    }

    static HANDLE __stdcall CreateFileForCdStream(
        LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
        LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
        DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
    {
        LPCSTR lpActualFileName = streaming.GetCdStreamPath(lpFileName);
        plugin_ptr->Log("Opening file for streaming \"%s\"", lpActualFileName);
        return CreateFileA(
            lpActualFileName, dwDesiredAccess, dwShareMode,
            lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
    }

    
    // Reproduces the code @6BF741
    void FixBikeSuspPtr(char* m_pColData)
    {
        *(char*)(m_pColData + 6) = 4;
        char* ptr = injector::cstd<char*(size_t)>::call<0x72F420>(128); // CMemoryMgr::Malloc
        *(char**)(m_pColData + 16) = ptr;
        *(uint32_t*)(ptr + 10) = 0x47C34FFFu;   // a float actually
        *(uint32_t*)(ptr + 8)  = 0x47C34FFFu;   // a float actually
    }
};



/*
 *  Streaming thread
 *      This thread reads pieces from cd images and in mod loader on disk files
 */
int __stdcall CdStreamThread()
{
    DWORD nBytesReaden;
    
    // Get reference to the addresses we'll use
    CdStreamInfo& cdinfo = *memory_pointer(0x8E3FEC).get<CdStreamInfo>();
    
    // Loop in search of things to load in the queue
    while(true)
    {
        int i = -1;
        CdStream* cd;
        bool bIsAbstract = false;
        CAbstractStreaming::AbctFileHandle* sfile = nullptr;
        
        // Wait until there's something to be loaded...
        WaitForSingleObject(cdinfo.semaphore, -1);
        
        // Take the stream index from the queue
        i = GetFirstInQueue(&cdinfo.queue);
        if(i == -1) continue;
        
        cd = &cdinfo.pStreams[i];
        cd->bInUse = true;          // Mark the stream as under work
        if(cd->status == 0)
        {
            // Setup vars
            uint32_t bsize  = cd->nSectorsToRead;
            uint64_t offset = uint64_t(cd->nSectorOffset)  << 11;   // translate 2KiB based offset to actual offset
            uint32_t size   = uint32_t(bsize) << 11;                // translate 2KiB based size to actual size
            HANDLE hFile    = (HANDLE) cd->hFile;
            bool bResult    = false;
            const char* filename = nullptr; int index = -1; // When abstract those fields are valid
            
            // Try to find abstract file from hFile
            if(true)
            {
                scoped_lock xlock(streaming.cs);
                auto it = std::find(streaming.stm_files.begin(), streaming.stm_files.end(), hFile);
                if(it != streaming.stm_files.end())
                {
                    bIsAbstract = true;
                    
                    // Setup vars based on abstract file
                    sfile  = &(*it);
                    offset = 0;
                    size   = (uint32_t) sfile->info.file->size;
                    bsize  = GetSizeInBlocks(size);
                    index  = sfile->index;
                    filename = sfile->info.file->filepath();
                }
            }
            
            
            // Setup overlapped structure
            LARGE_INTEGER offset_li;
            offset_li.QuadPart        = offset;
            cd->overlapped.Offset     = offset_li.LowPart;
            cd->overlapped.OffsetHigh = offset_li.HighPart;
            
            // Read the stream
            if(ReadFile(hFile, cd->lpBuffer, size, &nBytesReaden, &cd->overlapped))
            {
                bResult = true;
            }
            else
            {
                if(GetLastError() == ERROR_IO_PENDING)
                {
                    // This happens when the stream was open for async operations, let's wait until everything has been read
                    // As noted on MSDN [http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx], when
                    // you open a stream with FILE_FLAG_NO_BUFFERING  (R* does that with their cd streams) it gives you maximum
                    // performance if you use overlapped I/O
                    bResult = GetOverlappedResult(hFile, &cd->overlapped, &nBytesReaden, true) != 0;
                }
{'fraction_non_alphanumeric': 0.09093198992443324, 'fraction_numerical': 0.015029387069689336, 'mean_word_length': 1.9359132363815628, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2220207', 'n_tokens_mistral': 3574, 'n_tokens_neox': 3321, 'n_words': 945}