Jump to content

Garage Save eXtender


Recommended Posts

Garage Save eXtender (or GSX for short) is an ASI mod for GTA San Andreas that allows other mods to store more info/data for cars saved in garages.

 

Showing the Vehicle License Plate Save mod:

 

  • The data stored is identified by name and exclusive for the vehicle it belongs
  • You can use the GSX in mods CLEO, C/C++, Lua or CLEO and C/C++ (Portuguese)
  • GSX save files located in Documents/GTA San Andreas User Files/gsx

 

Code examples included in download.

 

Thread in Mixmods forum (Portuguese)

Download GSX (+API and examples)

 

Mods currently using GSX:

Download License Plate Save Mod ASI (requires the gsx.asi)

VehFuncs - new vehicle functions
[Lua] Vehicle Paint using RGB colors (Portuguese)

[Lua] Other vehicles painted with RGB colors (Portuguese)

[Lua] Gas stations (Portuguese)

 

Reserved data names:

_hash

  • Contains a unsigned 64bits integer hash for the vehicle

 

 

 

TODO:

  • Documentation of all functions
  • More tests in GSX.asi

 

Spoiler

 

gsx11.jpg

 

License Plate Save (with logging for debug) source code:

Spoiler

Requires:

GSX API (included in GSX download)

Plugin-SDK

LINK/2012's Injector


//#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <injector\injector.hpp>
#include <injector\assembly.hpp>
#include <injector\calling.hpp>
#include <injector\saving.hpp>
#include <game_sa\CVehicle.h>
#include <game_sa\CMatrix.h>
#include <game_sa\RenderWare.h>
#include <string>
#include "CStoredCar.h"
#include "GSXAPI.h"
#include <fstream>

static auto getVehicleModelInfoByID = injector::cstd<CVehicleModelInfo*(int id)>::call<0x00403DA0>;
auto CustomCarPlate_TextureCreate = injector::thiscall<bool(CVehicle *, CVehicleModelInfo *)>::call<0x006D10E0>;

std::fstream saveLicensePlateLog("saveLicensePlate.log", std::ios::out | std::ios::trunc);

void callback(const GSX::externalCallbackStructure *test)
{
	using namespace GSX;

	if (test->veh)
	{
		switch (test->status)
		{
		case GSX::LOAD_CAR:
		{
			if (dataToLoadExists(test->veh, "carplate"))
			{
				const char *plateText = (const char *)getSavedData(test->veh, "carplate");

				if (plateText != nullptr)
				{
					CVehicleModelInfo *info = getVehicleModelInfoByID(test->veh->m_wModelIndex);

					strncpy(info->m_plateText, plateText, 8u);

					if (CustomCarPlate_TextureCreate(test->veh, info))
					{
						//RwFrame;
						//RpClump;
						char testPlate[9] = { 0 };

						strncpy(testPlate, plateText, 8u);
						testPlate[8] = 0;

						saveLicensePlateLog << std::to_string((uintptr_t)test->veh) << " GTA SA function CustomCarPlate_TextureCreate: OK  " << testPlate << std::endl;
					}
					else
					{
						//MessageBoxA(0, "error plate", "", 0);
						saveLicensePlateLog << std::to_string((uintptr_t)test->veh) << " GTA SA function CustomCarPlate_TextureCreate: error" << std::endl;
					}
				}
				else
				{
					saveLicensePlateLog << std::to_string((uintptr_t)test->veh) << " plateText is nullptr " << std::endl;
				}
			}
			else
			{
				saveLicensePlateLog << std::to_string((uintptr_t)test->veh) << " GSX carplate not exists" << std::endl;
			}

			break;
		}

		case GSX::SAVE_CAR:
		{
			if (test->veh->m_pCustomCarPlate)
			{
				setDataToSaveLater(test->veh, "carplate", 8, test->veh->m_pCustomCarPlate->name, true);

				char testPlate[9] = {0};

				strncpy(testPlate, test->veh->m_pCustomCarPlate->name, 8u);
				testPlate[8] = 0;

				saveLicensePlateLog << std::to_string((uintptr_t)test->veh) << " saving license plate " << testPlate << std::endl;
			}
			else
			{
				saveLicensePlateLog << std::to_string((uintptr_t)test->veh) << " veh->m_pCustomCarPlate is nullptr" << std::endl;
			}
			break;
		}

		default:
			saveLicensePlateLog << "GSX unknow status" << std::endl;
			break;
		}
	}
	else
	{
		saveLicensePlateLog << "GSX Veh is nullptr" << std::endl;
	}
}

void onload(int id)
{
	static bool loaded = false;

	if (!loaded)
	{
		saveLicensePlateLog << "ASI date/time: " __DATE__ " " __TIME__ << std::endl;

		loaded = true;

		addNotifyCallback(callback);
	}
}

void inject()
{
	injector::save_manager::on_load(onload);
}

BOOL WINAPI DllMain(
	_In_  HINSTANCE hinstDLL,
	_In_  DWORD fdwReason,
	_In_  LPVOID lpvReserved
	){
	if (fdwReason == DLL_PROCESS_ATTACH) inject();


	return true;
}

 

 

 

 

 

Edited by fabio3
Link to comment
https://gtaforums.com/topic/925563-garage-save-extender/
Share on other sites

  • 2 years later...
  • 3 years later...

 I Don't Know Why But the Game Crashes When I Try to Use the Function dataToLoadExists by CLEO
My Script:

{$CLEO}

0AA2: 0@ = load_library "gsx.asi" // IF and SET                                                                                  
0AA4: 6@ = get_proc_address "getNewCarGrgForeach" library 0@ // IF and SET 
0AA4: 7@ = get_proc_address "getLoadDataByVehPtr" library 0@ // IF and SET
0AA4: 8@ = get_proc_address "dataToLoadExists" library 0@ // IF and SET
0AA4: 10@ = get_proc_address "pushDirectlyToSavedData" library 0@ // IF and SET

const
   LOAD_CAR = 0
   SAVE_CAR = 1
end


while true
   wait 0        
   
   // Other things
   
   0AC7: 13@ = var 16@ offset    // carInfo - 8 bytes
   0AC6: 14@ = label @positionRegister offset   // 8 bytes
   while true
       0AA7: call_function 6@ num_params 2 pop 2 13@ 14@ retorno 15@  // getNewCarGrgForeach / GSX::getNewCarForeach(i, out)
       if 15@ <> 0 
       jf break
                
       if
       17@ == 0 
       then
       23@ = call_function_return {address} 8@ {numParams} 2 {pop} 2 {funcParams} 16@ 'TESTVAR'
       if
       23@ == 1
       then
       22@ = call_function_return {address} 7@ {numParams} 2 {pop} 2 {funcParams} 16@ 'TESTVAR'
       if 
       22@ <> 0 
       then
       0AD0: show_formatted_text_lowpriority "Test Var %i" time 4000 22@
       end
       end   
       end   
       if
       17@ == 1 
       then
       call_function {address} 10@ {numParams} 5 {pop} 5 {funcParams} 16@ 'TESTVAR' 1 4 true
       print_string {text} "Value Saved!" {time} 4000  
       end 
       
   end
   
   
   // Other things
end

:carInfo
hex
   00 00 00 00  // veh ptr
   00 00 00 00  // status
end

:positionRegister
hex
    00 00 00 00 00 00 00 00
end

SCRLOG Log:

00000135&0: [0AC7] GET_VAR_POINTER l16(0)  -> 27048020
00000143&0: [0AC6] GET_LABEL_POINTER -403 -> 196535771
00000153&0: [0AA7] CALL_FUNCTION_RETURN 0x6D754490 2 2 27048020 196535771 -> 1
00000172&0: [00D6] IF 0
00000176&0: [8039] NOT l15(1) == 0    // TRUE
00000183&1: [004D] GOTO_IF_FALSE -388
00000190&1: [00D6] IF 0
00000194&0: [0039] l17(0) == 0    // TRUE
00000201&1: [004D] GOTO_IF_FALSE -316
00000208&1: [0AA7] CALL_FUNCTION_RETURN 0x6D750AD0 2 2 147401896 "TESTVAR"
Link to comment
https://gtaforums.com/topic/925563-garage-save-extender/#findComment-1072445247
Share on other sites

Ok, I managed to solve the problem, I just had to invert the order of the parameters in the functions
Here is the code:

{$CLEO}

0AA2: 0@ = load_library "gsx.asi" // IF and SET                                                                                  
0AA4: 6@ = get_proc_address "getNewCarGrgForeach" library 0@ // IF and SET 
0AA4: 7@ = get_proc_address "getLoadDataByVehPtr" library 0@ // IF and SET
0AA4: 8@ = get_proc_address "dataToLoadExists" library 0@ // IF and SET
0AA4: 10@ = get_proc_address "pushDirectlyToSavedData" library 0@ // IF and SET

const
   LOAD_CAR = 0
   SAVE_CAR = 1
end


while true
   wait 0        
   
   // Other things
   
   0AC7: 13@ = var 16@ offset    // carInfo - 8 bytes
   0AC6: 14@ = label @positionRegister offset   // 8 bytes
   while true
       0AA7: call_function 6@ num_params 2 pop 2 13@ 14@ retorno 15@  // getNewCarGrgForeach / GSX::getNewCarForeach(i, out)
       if 15@ <> 0 
       jf break
          
       if
       17@ == 1 
       then
       print_string 'Value Saved!' 2000
       else
       call_function_return {address} 8@ {numParams} 2 {pop} 2 {funcParams} "TESTVAR" 16@ 23@
       print_string 'Value Loaded!' 2000
       if
       23@ <> 0
       then
       call_function_return {address} 7@ {numParams} 2 {pop} 2 {funcParams} "TESTVAR" 16@ 22@
       0A8D: 22@ = read_memory 22@ size 4 virtual_protect 1
       0AD0: show_formatted_text_lowpriority "Test Var %i" time 4000 22@
       end   
       end
       
   end
   
   
   // Other things
end

:carInfo
hex
   00 00 00 00  // veh ptr
   00 00 00 00  // status
end

:carValue
hex
    00
end

:buflicenseplate
hex
   00
end

:positionRegister
hex
    00 00 00 00 00 00 00 00
end


As for some reason the function of saving the date in the vehicle was not taking effect when I closed the garage, I had to create another script that saves the date in the vehicle all the time
Here is the script:

{$CLEO}
{$USE CLEO+}

0AA2: 0@ = load_library "gsx.asi" // IF and SET
0AA4: 10@ = get_proc_address "pushDirectlyToSavedData" library 0@ // IF and SET

0000:

:MAIN
wait 0
29@ = 0
while get_any_car_no_save_recursive 29@ progress_to 29@ car_to 12@
if
056E:   car 12@ defined
then
0227: 28@ = car 12@ health
//0AD0: show_formatted_text_lowpriority "Test Var %i" time 4000 28@
       0AC6: 25@ = label @carValue offset   // 8 bytes
       0A97: 16@ = vehicle 12@ struct
       0A8C: write_memory 25@ size 4 value 1 virtual_protect 1
       call_function {address} 10@ {numParams} 4 {pop} 4 {funcParams} 25@ 4 "TESTVAR" 16@
end
end
jump @MAIN

:carValue
hex
    00 00 00 00
end
Link to comment
https://gtaforums.com/topic/925563-garage-save-extender/#findComment-1072446216
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • 0 User Currently Viewing
    0 members, 0 Anonymous, 0 Guests

×
×
  • Create New...

Important Information

By using GTAForums.com, you agree to our Terms of Use and Privacy Policy.