// UNTESTED example file by thaCURSEDpie
// 2012-06-02
//
// Should work though, it at least compiles without warnings and errors.
namespace Explosia_Example
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using GTA;
using Explosia_DLL;
public class Explosia_Example : Script
{
// Current process (== GTAIV.exe, or EFLC.exe in case of EFLC)
private Process currentProcess;
// Store base address here, because getting the .BaseAddress property is expensive!
// (I learned this the hard way)
private IntPtr baseAddress;
// List of the structures we're going to create
private List<CEditableStruct> structures;
// Path we use to look for our input files
string searchStructPath = ".\\explosia\\structureinfo";
// File extension to look for
string structFileExtension = ".sif";
public Explosia_Example()
{
this.GeneralInfo = "Example for Explosia by thaCURSEDpie";
// Console commands.
// Exercise for the reader interested in learning basic C#: add a cmd which rebuilds structures from a specific directory.
BindConsoleCommand("expl_liststructs", this.listStructs_console, "Lists all currently loaded structures. Usage: expl_liststructs");
BindConsoleCommand("expl_listparams", this.listParams_console, "Lists a structure's parameters. Usage: expl_listparams <structure name>");
BindConsoleCommand("expl_setparam", this.setParam_console, "Sets a param value. Usage: expl_setparam <strucure name> <param name> <index to affect> <new value>");
BindConsoleCommand("expl_getparam", this.setParam_console, "Gets a param value. Usage: expl_getparam <strucure name> <param name> <index to look at>");
//////-------------------
// Example input could be:
// > expl_set param CVehicleInfo m_fDriveForce 0 0.1337
// Which would change the Admiral's (first car in the list, see the list on gtamodding.com) m_fDriveForce to 0.1337
// Init stuff
this.currentProcess = Process.GetCurrentProcess();
this.baseAddress = this.currentProcess.MainModule.BaseAddress;
// Build stuff :)
this.structures = this.buildStructures(this.searchStructPath);
}
// Get a structure by name (just a handy function, nothing fancy)
private CEditableStruct getStructByName(string name)
{
// Just iterate through all the structures, until we find a match.
for (int i = 0; i < this.structures.Count; i++)
{
if (this.structures[i].Name == name)
{
return this.structures[i];
}
}
return null;
}
// Console wrapper for the getParamValue function
private void getParam_console(ParameterCollection p)
{
if (p.Count != 3)
{
Game.Console.Print("Usage: expl_getparam <strucure name> <param name> <index to affect>");
return;
}
string value = string.Empty;
int retVal = this.getParamValue(p.ToString(0), p.ToString(1), p.ToInteger(2), out value);
if (retVal == 0)
{
Game.Console.Print(string.Format("Value:\n{0}", value));
}
else
{
Game.Console.Print(string.Format("[EXPLOSIA]: Getting value failed with error code {0}!", retVal));
}
}
// Console wrapper for the setParamValue function
private void setParam_console(ParameterCollection p)
{
if (p.Count != 4)
{
Game.Console.Print("Usage: expl_setparam <strucure name> <param name> <index to affect> <new value>");
return;
}
this.setParamValue(p.ToString(0), p.ToString(1), p.ToInteger(2), p.ToString(3));
}
// List all created structures
private void listStructs_console(ParameterCollection p)
{
Game.Console.Print("[EXPLOSIA]: Showing loaded structures:");
for (int i = 0; i < this.structures.Count; i++)
{
Game.Console.Print(this.structures[i].Name);
}
}
// Console wrapper for listParams structure
private void listParams_console(ParameterCollection p)
{
if (p.Count < 1)
{
Game.Console.Print("[EXPLOSIA]: Error! You must specify a structure!");
return;
}
this.listParams(p.ToString(0));
}
// Example how to get values
private int getParamValue(string structure, string param, int index, out string value)
{
// We get the relevant structure
CEditableStruct s = this.getStructByName(structure);
value = string.Empty;
// Always check
if (s == null)
{
Game.Console.Print(string.Format("[EXPLOSIA]: Error! No structure with name {0} found!", structure));
return 0xBADBAD;
}
// Voila, done.
return s.GetParamValueAsString(this.currentProcess.Handle, this.baseAddress, param, index, out value);
}
// Example how to change values
private void setParamValue(string structure, string param, int index, string newValue)
{
// We get the structure.
CEditableStruct s = this.getStructByName(structure);
// Always check.
if (s == null)
{
Game.Console.Print(string.Format("[EXPLOSIA]: Error! No structure with name {0} found!", structure));
return;
}
// Let's do it.
int retVal = s.SetParamValue(this.currentProcess.Handle, this.baseAddress, param, index, newValue);
// For the sake of inconcistency, lol
if (retVal == 0)
{
Game.Console.Print(string.Format("[EXPLOSIA]: Param value successfully changed!"));
}
else
{
Game.Console.Print(string.Format("[EXPLOSIA]: Setting parameter value failed with error code {0}!", retVal));
}
}
// List all params in a structure
private void listParams(string structure)
{
// get the structure
CEditableStruct s = this.getStructByName(structure);
// Always check
if (s == null)
{
Game.Console.Print(string.Format("[EXPLOSIA]: Error! No structure with name {0} found!", structure));
return;
}
Game.Console.Print(string.Format("Param info for {0}. # params: {1}. Names:", structure, s.NumParams));
SParameter p;
// Just loop through all params
for (int i = 0; i < s.NumParams; i++)
{
// I don't check if the param != null, because the structures are not being changed after they have been created
s.GetParamByIndex(i, out p);
Game.Console.Print(s.Name);
}
}
// Build the structures from the input files.
private List<CEditableStruct> buildStructures(string searchDir)
{
// Set up input-file search.
DirectoryInfo di = new DirectoryInfo(searchDir);
FileInfo[] fi = di.GetFiles("*" + this.structFileExtension);
int numStructsLoaded = 0;
List<CEditableStruct> structs = new List<CEditableStruct>();
// We must use the right input file for the right GTA version, otherwise we might be working with wrong offsets.
string version = this.currentProcess.MainModule.FileVersionInfo.FileVersion;
// Because the FileVersion property gives versions containing spaces and commas instead of just periods.
version = version.Replace(" ", string.Empty);
version = version.Replace(",", ".");
// Loop through all input files.
for (int i = 0; i < fi.Length; i++)
{
// Initialize vars
CEditableStruct structure = null;
// Variable containing data to be used if offset needs to be searched for
SArraySearchData sData = new SArraySearchData();
int errorLine = 0;
// We create a structure from an inputfile. Easy as can be :).
int retVal = CInputParser.CreateStructure(
fi[i].FullName, // Note! FULL path to input file!
this.currentProcess,
version,
out structure,
ref sData,
ref errorLine);
// Success
if (retVal == 0)
{
structs.Add(structure);
Game.Console.Print("[EXPLOSIA]: Structure info for '" + structure.Name + "' was successfully loaded.");
numStructsLoaded++;
}
else if (retVal == 20)
{
// Version mismatch or no offset specified. We must search for the offset ourselves.
Game.Console.Print("[EXPLOSIA]: Searching array address of '" + structure.Name + "'...");
int addr = 0;
// Searching is done by calling this function
// (this can take a long while sometimes :( )
retVal = CRemoteHelper.FindArrayAddress(this.currentProcess, sData, out addr);
// Success
if (retVal == 0)
{
structure.ArrayOffset = addr - (int)this.baseAddress;
structs.Add(structure);
Game.Console.Print("[EXPLOSIA]: Address found!");
numStructsLoaded++;
}
else
{
// Boohoo!
Game.Console.Print("[EXPLOSIA]: Address NOT found!");
}
}
else if (retVal == 6)
{
// File is not made for GTAIV.exe (or EFLC.exe in case of EFLC)
Game.Console.Print("[EXPLOSIA]: file '" + fi[i].Name + "' is not meant to be used with '" + this.currentProcess.ProcessName + ".exe'. This file is being ignored.");
}
else
{
// some other error I don't care to handle here.
Game.Console.Print("[EXPLOSIA]: Error loading info from'" + fi[i].Name + "'. Code: " + retVal.ToString() + " at line " + errorLine.ToString() + ".");
}
}
Game.Console.Print(string.Format("finished parsing input files and building structs.\n# Structs loaded: {0}", numStructsLoaded));
return structs;
}
}
}