Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Allow load custom IMG containers #1677

Merged
merged 85 commits into from
Apr 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
fdbf965
Added MTA interface
TheNormalnij Sep 13, 2020
227f281
Allow to load custom IMG
TheNormalnij Sep 24, 2020
dadaec6
Added resource IMG root
TheNormalnij Sep 25, 2020
88b758e
Added engineSetModelIMG function
TheNormalnij Sep 25, 2020
dff4812
Added engineGetModelTXDID and EngineSetModelTXDID
TheNormalnij Sep 26, 2020
d7f42c6
Fix typos
TheNormalnij Sep 26, 2020
bfa404d
Allow allocating new objects
TheNormalnij Sep 26, 2020
24ec997
Revert "Allow allocating new objects"
TheNormalnij Sep 28, 2020
7491889
Improved CClientIMG
TheNormalnij Oct 12, 2020
947e614
Improved load function
TheNormalnij Oct 13, 2020
2b3eac9
Changed value for fail case in CStreamingSA
TheNormalnij Oct 13, 2020
aab8152
Improved Lua API for engineSetModelIMG
TheNormalnij Oct 13, 2020
b52d9de
Added some unlink interface
TheNormalnij Oct 13, 2020
719b273
Improved unlink interface
TheNormalnij Oct 13, 2020
acff78f
Added IMG manager, fix build
TheNormalnij Oct 15, 2020
ebf4cf1
Add new IMG's to list
TheNormalnij Oct 15, 2020
ae8185c
Added CClientIMG::IsStreamed()
TheNormalnij Oct 16, 2020
6464081
Fix typo
TheNormalnij Oct 16, 2020
94a8ecd
Added EngineAddImage and EngineRemoveImage
TheNormalnij Oct 16, 2020
4de39c8
Added EngineImageGetFilesCount and EngineImageGetFileList
TheNormalnij Oct 16, 2020
f5a773a
Added img:getFile
TheNormalnij Oct 16, 2020
d41e491
Fix CClientIMG::GetFileID()
TheNormalnij Oct 16, 2020
d7f69eb
Disable engineSetModelTXDID function
TheNormalnij Oct 16, 2020
7d26e07
Small API changes
TheNormalnij Oct 16, 2020
4d63000
Added img:linkModel()
TheNormalnij Oct 16, 2020
fe0908c
Fix missing API
TheNormalnij Oct 16, 2020
aff0a1a
Refactor some code
TheNormalnij Oct 17, 2020
d65d28f
Fix build
TheNormalnij Oct 17, 2020
5f99829
Refactor CStreamingSA
TheNormalnij Oct 17, 2020
42097a7
Fix comment
TheNormalnij Oct 17, 2020
e43b294
Fix wrong uiStreamHandlerID
TheNormalnij Oct 17, 2020
a8fe35d
Refactror std::vector<tLinkedModelRestoreInfo*> to std::list<tLinkedM…
TheNormalnij Oct 17, 2020
6bda318
Merge branch 'master' into img_open
TheNormalnij Oct 28, 2020
36960a0
Merge remote-tracking branch 'mta-home/master' into img_open
TheNormalnij Nov 12, 2020
38ad586
Fix build
TheNormalnij Nov 12, 2020
9644902
Used new parser for engineImage*
TheNormalnij Nov 13, 2020
4f958d7
Fix API
TheNormalnij Nov 13, 2020
3ff97d8
Fix removed engineRestreamWorld
TheNormalnij Nov 13, 2020
4c3aceb
Removed unused TXD stuff
TheNormalnij Nov 13, 2020
ef0a3ea
engineImageLinkModel replaced to engineImageLinkDFF and engineImageLi…
TheNormalnij Nov 13, 2020
f45931e
Fix OOP API
TheNormalnij Nov 13, 2020
ba66c29
Fix API
TheNormalnij Nov 13, 2020
c4fd582
Fixed restore functions
TheNormalnij Nov 13, 2020
771160f
Fix missing stuff
TheNormalnij Nov 13, 2020
50aad93
Removed unused stuff
TheNormalnij Nov 13, 2020
170e256
Merge branch 'master' into img_open
TheNormalnij Dec 5, 2020
79b6941
Refactor CClientIMG
Pirulax Dec 6, 2020
aafd0c8
Refactor Lua API for Images
Pirulax Dec 6, 2020
2555c4d
Fix warning in CClientIMG
Pirulax Dec 6, 2020
4ae02ca
Change lua::Push std::string to std::string_view, thus adding support…
Pirulax Dec 6, 2020
e638503
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue…
Pirulax Dec 6, 2020
8180adc
Fix ms_aInfoForModel - address was invalid, and caused a crash after …
Pirulax Dec 6, 2020
beef9ff
Cleanup CStreamingSA::ReinitStreaming
Pirulax Dec 6, 2020
eca68ea
Cleanup CStreamingSA::SetStreamingInfoForModelId and add a note
Pirulax Dec 6, 2020
046b21e
Add GetUnusedArchieve()
Pirulax Dec 6, 2020
eb11e40
Add GetUnusedStreamHandle()
Pirulax Dec 6, 2020
2b6e1d7
Refactor CStreamingSA::AddArchive
Pirulax Dec 6, 2020
987980b
Rename GetStreamingInfoFromModelID to GetStreamingInfo
Pirulax Dec 6, 2020
8be4de2
Rename SetStreamingInfoForModelId to SetStreamingInfo
Pirulax Dec 6, 2020
3f927bb
Addendum to SetStreamingInfo rename
Pirulax Dec 6, 2020
a2ff05e
Addendum to SetStreamingInfo rename..
Pirulax Dec 6, 2020
3d819ed
Replace CStreamingInfo::Reset() with CStreamingInfo{} + default inita…
Pirulax Dec 6, 2020
e76ed7a
fix narrowing extension error in CStreaming.h
Pirulax Dec 6, 2020
af6cbe5
Fix issues caused by argument parser - number on stack was converted …
Pirulax Dec 8, 2020
1aba45d
Fix compiler warnings
Pirulax Dec 8, 2020
e6b9834
Merge branch 'master' into img_open
Apr 10, 2021
0a2d946
Fix conflicts
Apr 10, 2021
c580386
fix typo
Apr 10, 2021
05c7c74
Added CStreamingSA::SetStreamingBufferSize
Apr 11, 2021
d7b0a4b
Increase buffer size for new streamed img archive
Apr 11, 2021
a003e33
Replace variable name
Apr 11, 2021
93bb916
Remove unnecessary check
Apr 11, 2021
55d69e2
Used std
Apr 11, 2021
5160cc7
engineImageGetFileList to engineImageGetFiles
Apr 11, 2021
feb67b4
Removed unnecessary headers content
Apr 11, 2021
26785d6
Used void* for buffers
Apr 12, 2021
ff1f03c
Allow decrease buffer size
Apr 24, 2021
0abd8ab
Don't close thread
Apr 25, 2021
ea11b4c
Added additional check
Apr 25, 2021
d6af906
Update Client/mods/deathmatch/logic/CClientIMGManager.cpp
TheNormalnij Apr 25, 2021
5407b7e
Added security checks
Apr 25, 2021
e3efe9d
exception > invalid_argument
TheNormalnij Apr 25, 2021
d390073
ms_streamingBufferSize > ms_streamingHalfOfBufferSize
TheNormalnij Apr 25, 2021
fcbb4da
Merge branch 'master' into img_open
TheNormalnij Dec 24, 2022
8b51776
Merge branch 'master' into img_open
patrikjuvonen Jan 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Client/game_sa/CModelInfoSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ bool CModelInfoSA::IsValid()

bool CModelInfoSA::IsAllocatedInArchive()
{
return pGame->GetStreaming()->GetStreamingInfoFromModelId(m_dwModelID)->sizeInBlocks > 0;
return pGame->GetStreaming()->GetStreamingInfo(m_dwModelID)->sizeInBlocks > 0;
}

float CModelInfoSA::GetDistanceFromCentreOfMassToBaseOfModel()
Expand Down Expand Up @@ -753,7 +753,7 @@ void CModelInfoSA::StaticFlushPendingRestreamIPL()
for (it = removedModels.begin(); it != removedModels.end(); it++)
{
pGame->GetStreaming()->RemoveModel(*it);
pGame->GetStreaming()->GetStreamingInfoFromModelId(*it)->loadState = 0;
pGame->GetStreaming()->GetStreamingInfo(*it)->loadState = 0;
}
}

Expand Down Expand Up @@ -1435,10 +1435,10 @@ void CModelInfoSA::SetVoice(const char* szVoiceType, const char* szVoice)

void CModelInfoSA::CopyStreamingInfoFromModel(ushort usBaseModelID)
{
CStreamingInfo* pBaseModelStreamingInfo = pGame->GetStreaming()->GetStreamingInfoFromModelId(usBaseModelID);
CStreamingInfo* pTargetModelStreamingInfo = pGame->GetStreaming()->GetStreamingInfoFromModelId(m_dwModelID);
CStreamingInfo* pBaseModelStreamingInfo = pGame->GetStreaming()->GetStreamingInfo(usBaseModelID);
CStreamingInfo* pTargetModelStreamingInfo = pGame->GetStreaming()->GetStreamingInfo(m_dwModelID);

pTargetModelStreamingInfo->Reset();
*pTargetModelStreamingInfo = CStreamingInfo{};
pTargetModelStreamingInfo->archiveId = pBaseModelStreamingInfo->archiveId;
pTargetModelStreamingInfo->offsetInBlocks = pBaseModelStreamingInfo->offsetInBlocks;
pTargetModelStreamingInfo->sizeInBlocks = pBaseModelStreamingInfo->sizeInBlocks;
Expand Down Expand Up @@ -1529,7 +1529,7 @@ void CModelInfoSA::DeallocateModel(void)
}

ppModelInfo[m_dwModelID] = nullptr;
pGame->GetStreaming()->GetStreamingInfoFromModelId(m_dwModelID)->Reset();
*pGame->GetStreaming()->GetStreamingInfo(m_dwModelID) = CStreamingInfo{};
}
//////////////////////////////////////////////////////////////////////////////////////////
//
Expand Down
156 changes: 149 additions & 7 deletions Client/game_sa/CStreamingSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,18 @@
#include <core/CCoreInterface.h>
#include "CStreamingSA.h"
#include "CModelInfoSA.h"
#include "Fileapi.h"
#include "processthreadsapi.h"

extern CCoreInterface* g_pCore;

// count: 26316 in unmodified game
CStreamingInfo* CStreamingSA::ms_aInfoForModel = (CStreamingInfo*)CStreaming__ms_aInfoForModel;
CStreamingInfo (&CStreamingSA::ms_aInfoForModel)[26316] = *(CStreamingInfo(*)[26316])0x8E4CC0;
HANDLE (&CStreamingSA::m_aStreamingHandlers)[32] = *(HANDLE(*)[32])0x8E4010; // Contains open files
CArchiveInfo (&CStreamingSA::ms_aAchiveInfo)[8] = *(CArchiveInfo(*)[8])0x8E48D8; // [8][0x30]
HANDLE* phStreamingThread = (HANDLE*)0x8E4008;
uint32 (&CStreamingSA::ms_streamingHalfOfBufferSize) = *(uint32*)0x8E4CA8;
void* (&CStreamingSA::ms_pStreamingBuffer)[2] = *(void*(*)[2])0x8E4CAC;

namespace
{
Expand Down Expand Up @@ -149,17 +156,152 @@ void CStreamingSA::RequestSpecialModel(DWORD model, const char* szTexture, DWORD
}
}

CStreamingInfo* CStreamingSA::GetStreamingInfoFromModelId(uint32 id)
void CStreamingSA::ReinitStreaming()
{
return &ms_aInfoForModel[id];
typedef int(__cdecl * Function_ReInitStreaming)();
((Function_ReInitStreaming)(0x40E560))();
}

void CStreamingSA::ReinitStreaming()
// ReinitStreaming should be called after this.
// Otherwise the model wont be restreamed
// TODO: Somehow restream a single model instead of the whole world
void CStreamingSA::SetStreamingInfo(uint modelid, unsigned char usStreamID, uint uiOffset, ushort usSize, uint uiNextInImg)
{
typedef int(__cdecl * Function_ReInitStreaming)();
Function_ReInitStreaming reinitStreaming = (Function_ReInitStreaming)(0x40E560);
CStreamingInfo* pItemInfo = GetStreamingInfo(modelid);

// Change nextInImg field for prev model
for (CStreamingInfo& info : ms_aInfoForModel)
{
if (info.archiveId == pItemInfo->archiveId)
{
// Check if the block after `info` is the beginning of `pItemInfo`'s block
if (info.offsetInBlocks + info.sizeInBlocks == pItemInfo->offsetInBlocks)
{
info.nextInImg = -1;
break;
}
}
}

pItemInfo->archiveId = usStreamID;
pItemInfo->offsetInBlocks = uiOffset;
pItemInfo->sizeInBlocks = usSize;
pItemInfo->nextInImg = uiNextInImg;
}

CStreamingInfo* CStreamingSA::GetStreamingInfo(uint modelid)
{
return &ms_aInfoForModel[modelid];
}

unsigned char CStreamingSA::GetUnusedArchive()
{
// Get internal IMG id
// By default gta sa uses 6 of 8 IMG archives
for (size_t i = 6; i < 8; i++)
{
if (!GetArchiveInfo(i)->uiStreamHandleId)
return (unsigned char)i;
}
return -1;
}

unsigned char CStreamingSA::GetUnusedStreamHandle()
{
for (size_t i = 0; i < VAR_StreamHandlersMaxCount; i++)
{
if (m_aStreamingHandlers[i])
return (unsigned char)i;
}
return -1;
}

unsigned char CStreamingSA::AddArchive(const char* szFilePath)
{
const auto ucArchiveId = GetUnusedArchive();
if (ucArchiveId == -1)
return -1;

// Get free stream handler id
const auto ucStreamID = GetUnusedStreamHandle();
if (ucStreamID == -1)
return -1;

// Create new stream handler
const auto streamCreateFlags = *(DWORD*)0x8E3FE0;
HANDLE hFile = CreateFileA(
szFilePath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
streamCreateFlags | FILE_ATTRIBUTE_READONLY | FILE_FLAG_RANDOM_ACCESS,
NULL
);

if (hFile == INVALID_HANDLE_VALUE)
return -1;

// Register stream handler
m_aStreamingHandlers[ucStreamID] = hFile;

// Register archive data
ms_aAchiveInfo[ucArchiveId].uiStreamHandleId = (ucStreamID << 24);

return ucArchiveId;
}

void CStreamingSA::RemoveArchive(unsigned char ucArhiveID)
{
unsigned int uiStreamHandlerID = ms_aAchiveInfo[ucArhiveID].uiStreamHandleId >> 24;
if (!uiStreamHandlerID)
return;

ms_aAchiveInfo[ucArhiveID].uiStreamHandleId = 0;

CloseHandle(m_aStreamingHandlers[uiStreamHandlerID]);
m_aStreamingHandlers[uiStreamHandlerID] = NULL;
}

void CStreamingSA::SetStreamingBufferSize(uint32 uiBlockSize)
{
if (uiBlockSize == ms_streamingHalfOfBufferSize * 2)
return;

int pointer = *(int*)0x8E3FFC;
SGtaStream(&streaming)[5] = *(SGtaStream(*)[5])(pointer);

// Wait while streaming threads ends tasks
while (streaming[0].bInUse && streaming[1].bInUse)
Pirulax marked this conversation as resolved.
Show resolved Hide resolved

// Suspend streaming handle
SuspendThread(*phStreamingThread);

// Create new buffer
if (uiBlockSize & 1)
uiBlockSize++;

typedef void*(__cdecl * Function_CMemoryMgr_MallocAlign)(uint32 uiCount, uint32 uiAlign);
void* pNewBuffer = ((Function_CMemoryMgr_MallocAlign)(0x72F4C0))(uiBlockSize << 11, 2048);

// Copy data from old buffer to new buffer
uint uiCopySize = std::min(ms_streamingHalfOfBufferSize, uiBlockSize / 2);
MemCpyFast(pNewBuffer, (void*)ms_pStreamingBuffer[0], uiCopySize);
MemCpyFast((void*)(reinterpret_cast<int>(pNewBuffer) + 1024 * uiBlockSize), (void*)ms_pStreamingBuffer[1], uiCopySize);

typedef void(__cdecl * Function_CMemoryMgr_FreeAlign)(void* pos);
((Function_CMemoryMgr_FreeAlign)(0x72F4F0))(ms_pStreamingBuffer[0]);

ms_streamingHalfOfBufferSize = uiBlockSize / 2;

ms_pStreamingBuffer[0] = pNewBuffer;
ms_pStreamingBuffer[1] = (void*)(reinterpret_cast<int>(pNewBuffer) + 1024 * uiBlockSize);

streaming[0].pBuffer = ms_pStreamingBuffer[0];
streaming[1].pBuffer = ms_pStreamingBuffer[1];

reinitStreaming();
// Well done
ResumeThread(*phStreamingThread);
}

void CStreamingSA::MakeSpaceFor(std::uint32_t memoryToCleanInBytes)
Expand Down
47 changes: 45 additions & 2 deletions Client/game_sa/CStreamingSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,67 @@

#include <game/CStreaming.h>

#define VAR_StreamHandlersMaxCount 32
#define VAR_MaxArchives 8

#define FUNC_CStreaming__RequestModel 0x4087E0
#define FUNC_LoadAllRequestedModels 0x40EA10
#define FUNC_CStreaming__HasVehicleUpgradeLoaded 0x407820
#define FUNC_CStreaming_RequestSpecialModel 0x409d10


struct CArchiveInfo
{
char szName[40];
BYTE bUnknow = 1; // Only in player.img is 0. Maybe, it is DWORD value
BYTE bUnused[3];
DWORD uiStreamHandleId;
};

struct SGtaStream
{
uint32_t nSectorsOffset;
uint32_t nSectorsToRead;
void* pBuffer;
uint8_t bUnknow1;
uint8_t bLocked;
uint8_t bInUse;
uint8_t bUnknow2;
uint32_t uiStatus;
uint32_t handle;
uint32_t file;
uint8_t pad[20];
};
static_assert(sizeof(SGtaStream) == 0x30, "Invalid size for SGtaStream");

class CStreamingSA final : public CStreaming
{
private:
static CArchiveInfo* GetArchiveInfo(uint id) { return &ms_aAchiveInfo[id]; };
public:
void RequestModel(DWORD dwModelID, DWORD dwFlags);
void RemoveModel(std::uint32_t model) override;
void LoadAllRequestedModels(bool bOnlyPriorityModels = false, const char* szTag = NULL);
bool HasModelLoaded(DWORD dwModelID);
void RequestSpecialModel(DWORD model, const char* szTexture, DWORD channel);
void ReinitStreaming();
CStreamingInfo* GetStreamingInfoFromModelId(uint32 id);

CStreamingInfo* GetStreamingInfo(uint32 id);
void SetStreamingInfo(uint32 modelid, unsigned char usStreamID, uint uiOffset, ushort usSize, uint uiNextInImg = -1);
unsigned char GetUnusedArchive();
unsigned char GetUnusedStreamHandle();
unsigned char AddArchive(const char* szFilePath);
void RemoveArchive(unsigned char ucStreamHandler);
void SetStreamingBufferSize(uint32 uiSize);
uint32 GetStreamingBufferSize() { return ms_streamingHalfOfBufferSize * 2; };

void MakeSpaceFor(std::uint32_t memoryToCleanInBytes) override;
std::uint32_t GetMemoryUsed() const override;

private:
static CStreamingInfo* ms_aInfoForModel; // count: 26316 in unmodified game
static void* (&ms_pStreamingBuffer)[2];
static uint32 (&ms_streamingHalfOfBufferSize);
static CStreamingInfo (&ms_aInfoForModel)[26316]; // count: 26316 in unmodified game
static HANDLE (&m_aStreamingHandlers)[32];
static CArchiveInfo (&ms_aAchiveInfo)[8];
};
1 change: 1 addition & 0 deletions Client/mods/deathmatch/StdInc.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
#include <CClientStreamSectorRow.h>
#include <CClientTask.h>
#include <CClientTXD.h>
#include <CClientIMG.h>
#include <CClientIFP.h>
#include <CClientWater.h>
#include <CClientWeapon.h>
Expand Down
1 change: 1 addition & 0 deletions Client/mods/deathmatch/logic/CClientColManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ void CClientColManager::DoHitDetectionForColShape(CClientColShape* pShape)
case CCLIENTDFF:
case CCLIENTCOL:
case CCLIENTTXD:
case CCLIENTIMG:
case CCLIENTSOUND:
break;
default:
Expand Down
4 changes: 3 additions & 1 deletion Client/mods/deathmatch/logic/CClientEntity.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ enum eClientEntityType
CCLIENTIFP,
CCLIENTVECTORGRAPHIC,
CCLIENTUNKNOWN,
CCLIENTIMG,
};

class CEntity;
Expand Down Expand Up @@ -140,7 +141,8 @@ enum eCClientEntityClassTypes
CLASS_CClientWeapon,
CLASS_CClientEffect,
CLASS_CClientPointLights,
CLASS_CClientSearchLight
CLASS_CClientSearchLight,
CLASS_CClientIMG,
};

class CClientEntity : public CClientEntityBase
Expand Down
3 changes: 3 additions & 0 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,9 @@ void CClientGame::DoPulses()

// Initialize the game
g_pCore->GetGame()->Initialize();

// Save default streamer buffer size in IMG manager
m_pManager->GetIMGManager()->InitDefaultBufferSize();
}

unsigned char ucError = g_pNet->GetConnectionError();
Expand Down
Loading