//
// ISXTesty
//
// Version guideline: YYYYMMDD
// Add lettering to the end to indicate a new version on the same date, such as 20060305a, 20060305b, etc
// You can also use a standard version numbering system such as 1.00, 1.01, etc.
// Be aware that for the versioning system, this text is simply compared to another version text from the
// same extension to check for new versions -- if this version text comes before the compared text (in a
// dictionary), then an update is available. Equal text means the version is up to date. After means this
// is newer than the compared version. With that said, use whatever version numbering system you'd like.
#define EXTENSION_VERSION "20060617"
#include <stdio.h>
#include "winsock2.h"
#include "ISXTesty.h"
#pragma comment(lib,"isxdk.lib")
// The mandatory pre-setup function. Our name is "ISXTesty", and the class is ISXTesty.
// This sets up a "ModulePath" variable which contains the path to this module in case we want it,
// and a "PluginLog" variable, which contains the path and filename of what we should use for our
// debug logging if we need it. It also sets up a variable "pExtension" which is the pointer to
// our instanced class.
ISXPreSetup("ISXTesty",ISXTesty);
// Basic LavishScript datatypes, these get retrieved on startup by our initialize function, so we can
// use them in our Top-Level Objects or custom datatypes
LSType *pStringType=0;
LSType *pIntType=0;
LSType *pUintType=0;
LSType *pBoolType=0;
LSType *pFloatType=0;
LSType *pTimeType=0;
LSType *pByteType=0;
LSType *pIntPtrType=0;
LSType *pBoolPtrType=0;
LSType *pFloatPtrType=0;
LSType *pBytePtrType=0;
ISInterface *pISInterface=0;
HISXSERVICE hPulseService;
HISXSERVICE hMemoryService;
HISXSERVICE hHTTPService;
HISXSERVICE hTriggerService;
HISXSERVICE hSystemService;
char Testy_Version[]=EXTENSION_VERSION;
// Forward declarations of callbacks
void __cdecl PulseService(bool Broadcast, unsigned int MSG, void *lpData);
void __cdecl MemoryService(bool Broadcast, unsigned int MSG, void *lpData);
void __cdecl TriggerService(bool Broadcast, unsigned int MSG, void *lpData);
void __cdecl HTTPService(bool Broadcast, unsigned int MSG, void *lpData);
void __cdecl SystemService(bool Broadcast, unsigned int MSG, void *lpData);
// The constructor of our class. General initialization cannot be done yet, because we're not given
// the pointer to the Inner Space interface until it is ready for us to initialize. Just set the
// pointer we have to the interface to 0. Initialize data members, too.
ISXTesty::ISXTesty(void)
{
}
// Free any remaining resources in the destructor. This is called when the DLL is unloaded, but
// Inner Space calls the "Shutdown" function first. Most if not all of the shutdown process should
// be done in Shutdown.
ISXTesty::~ISXTesty(void)
{
}
// Initialize is called by Inner Space when the extension should initialize.
bool ISXTesty::Initialize(ISInterface *p_ISInterface)
{
/*
* Most of the functionality in Initialize is completely optional and could be removed or
* changed if so desired. The defaults are simply a suggestion that can be easily followed.
*/
__try // exception handling. See __except below.
{
// Keep a global copy of the ISInterface pointer, which is for calling Inner Space API
pISInterface=p_ISInterface;
// Register the extension to make launching and updating the extension easy
RegisterExtension();
// retrieve basic LavishScript data types for use in ISXTesty data types
pStringType=pISInterface->FindLSType("string");
pIntType=pISInterface->FindLSType("int");
pUintType=pISInterface->FindLSType("uint");
pBoolType=pISInterface->FindLSType("bool");
pFloatType=pISInterface->FindLSType("float");
pTimeType=pISInterface->FindLSType("time");
pByteType=pISInterface->FindLSType("byte");
pIntPtrType=pISInterface->FindLSType("intptr");
pBoolPtrType=pISInterface->FindLSType("boolptr");
pFloatPtrType=pISInterface->FindLSType("floatptr");
pBytePtrType=pISInterface->FindLSType("byteptr");
// Connect to commonly used Inner Space services
ConnectServices();
// Register LavishScript extensions (commands, aliases, data types, objects)
RegisterCommands();
RegisterAliases();
RegisterDataTypes();
RegisterTopLevelObjects();
// Register (create) our own services
RegisterServices();
// Register any text triggers built into ISXTesty
RegisterTriggers();
EzDetourAPI(mydetour(),"ws2_32.dll",bind,0);
printf("ISXTesty version %s Loaded",Testy_Version);
return true;
}
// Exception handling sample. Exception handling should at LEAST be used in functions that
// are suspected of causing user crashes. This will help users report the crash and hopefully
// enable the extension developer to locate and fix the crash condition.
__except(EzCrashFilter(GetExceptionInformation(),"Crash in initialize routine"))
{
TerminateProcess(GetCurrentProcess(),0);
return 0;
}
/*
* EzCrashFilter takes printf-style formatting after the first parameter. The above
* could look something like this:
__except(EzCrashFilter(GetExceptionInformation(),"Crash in initialize routine (%s:%d)",__FILE__,__LINE__))
{
TerminateProcess(GetCurrentProcess(),0);
return 0;
}
* of course, the FILE and LINE macros would be the location of the exception handler, not the
* actual crash, but you should get the idea that extra parameters can be used as if EzCrashFilter
* was printf.
*
* EzCrashFilter will automatically produce a crash log (CrashLog.txt) and open it in notepad for
* non-breakpoint exceptions (and hopefully the user will report the crash to the extension developer).
* Your exception handler (the part within the {} under __except) should simply terminate the process
* and return from the function as in the sample. The return will not be hit, but the compiler will
* whine without it because it doesn't automatically know that the function will not return.
*/
}
void ISXTesty::mydetour()
{
//----------------------
// Initialize Winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR)
printf("Error at WSAStartup()\n");
//----------------------
// Create a SOCKET for listening for
// incoming connection requests
SOCKET ListenSocket;
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(27015);
//----------------------
// Bind the socket.
if (bind( ListenSocket,
(SOCKADDR*) &service,
sizeof(service)) == SOCKET_ERROR) {
printf("bind() failed.\n");
closesocket(ListenSocket);
return;
}
WSACleanup();
return;
}
// shutdown sequence
void ISXTesty::Shutdown()
{
// Disconnect from services we connected to
DisconnectServices();
// Unregister (destroy) services we created
UnRegisterServices();
// Remove LavishScript extensions (commands, aliases, data types, objects)
UnRegisterTopLevelObjects();
UnRegisterDataTypes();
UnRegisterAliases();
UnRegisterCommands();
}
/*
* Note that Initialize and Shutdown are the only two REQUIRED functions in your ISXInterface class.
* All others are for suggested breakdown of routines, and for example purposes.
*/
void ISXTesty::RegisterExtension()
{
// add this extension to, or update this extension's info in, InnerSpace.xml.
// This accomplishes a few things. A) The extension can be loaded by name (ISXTesty)
// no matter where it resides on the system. B) A script or extension can
// check a repository to determine if there is an update available (and update
// if necessary)
unsigned int ExtensionSetGUID=pISInterface->GetExtensionSetGUID("ISXTesty");
if (!ExtensionSetGUID)
{
ExtensionSetGUID=pISInterface->CreateExtensionSet("ISXTesty");
if (!ExtensionSetGUID)
return;
}
pISInterface->SetSetting(ExtensionSetGUID,"Filename",ModuleFileName);
pISInterface->SetSetting(ExtensionSetGUID,"Path",ModulePath);
pISInterface->SetSetting(ExtensionSetGUID,"Version",Testy_Version);
}
void ISXTesty::ConnectServices()
{
// connect to any services. Here we connect to "Pulse" which receives a
// message every frame (after the frame is displayed) and "Memory" which
// wraps "detours" and memory modifications
hPulseService=pISInterface->ConnectService(this,"Pulse",PulseService);
hMemoryService=pISInterface->ConnectService(this,"Memory",MemoryService);
// The HTTP service handles URL retrieval
hHTTPService=pISInterface->ConnectService(this,"HTTP",HTTPService);
// The Triggers service handles trigger-related functions, including the
// ability to pass text TO the trigger parser, as well as the ability to
// add triggers.
hTriggerService=pISInterface->ConnectService(this,"Triggers",TriggerService);
// The System service provides general system-related services, including
// a diagnostics message that allows the extension to insert diagnostic
// information for the "diagnostics" command, and extension crash logs.
hSystemService=pISInterface->ConnectService(this,"System",SystemService);
}
void ISXTesty::RegisterCommands()
{
// add any commands
// pISInterface->AddCommand("ISXTesty",CMD_ISXTesty,true,false);
#define COMMAND(name,cmd,parse,hide) pISInterface->AddCommand(name,cmd,parse,hide);
#include "Commands.h"
#undef COMMAND
}
void ISXTesty::RegisterAliases()
{
// add any aliases
}
void ISXTesty::RegisterDataTypes()
{
// add any datatypes
// pMyType = new MyType;
// pISInterface->AddLSType(*pMyType);
#define DATATYPE(_class_,_variable_,_inherits_) _variable_ = new _class_; pISInterface->AddLSType(*_variable_); _variable_->SetInheritance(_inherits_);
#include "DataTypeList.h"
#undef DATATYPE
}
void ISXTesty::RegisterTopLevelObjects()
{
// add any Top-Level Objects
//pISInterface->AddTopLevelObject("ISXTesty",TLO_ISXTesty);
#define TOPLEVELOBJECT(name,funcname) pISInterface->AddTopLevelObject(name,funcname);
#include "TopLevelObjects.h"
#undef TOPLEVELOBJECT
}
void ISXTesty::RegisterServices()
{
// register any services. Here we demonstrate a service that does not use a
// callback
// set up a 1-way service (broadcast only)
// hISXTestyService=pISInterface->RegisterService(this,"ISXTesty Service",0);
// broadcast a message, which is worthless at this point because nobody will receive it
// (nobody has had a chance to connect)
// pISInterface->ServiceBroadcast(this,hISXTestyService,ISXSERVICE_MSG+1,0);
#define SERVICE(_name_,_callback_,_variable_) _variable_=pISInterface->RegisterService(this,_name_,_callback_);
#include "Services.h"
#undef SERVICE
}
void ISXTesty::RegisterTriggers()
{
// add any Triggers
}
void ISXTesty::DisconnectServices()
{
// gracefully disconnect from services
if (hPulseService)
pISInterface->DisconnectService(this,hPulseService);
if (hMemoryService)
{
pISInterface->DisconnectService(this,hMemoryService);
// memory modifications are automatically undone when disconnecting
// also, since this service accepts messages from clients we should reset our handle to
// 0 to make sure we dont try to continue using it
hMemoryService=0;
}
if (hHTTPService)
{
pISInterface->DisconnectService(this,hHTTPService);
}
if (hTriggerService)
{
pISInterface->DisconnectService(this,hTriggerService);
}
if (hSystemService)
{
pISInterface->DisconnectService(this,hSystemService);
}
}
void ISXTesty::UnRegisterCommands()
{
// remove commands
// pISInterface->RemoveCommand("ISXTesty");
#define COMMAND(name,cmd,parse,hide) pISInterface->RemoveCommand(name);
#include "Commands.h"
#undef COMMAND
}
void ISXTesty::UnRegisterAliases()
{
// remove aliases
}
void ISXTesty::UnRegisterDataTypes()
{
// remove data types
#define DATATYPE(_class_,_variable_,_inherits_) pISInterface->RemoveLSType(*_variable_); delete _variable_;
#include "DataTypeList.h"
#undef DATATYPE
}
void ISXTesty::UnRegisterTopLevelObjects()
{
// remove Top-Level Objects
// pISInterface->RemoveTopLevelObject("ISXTesty");
#define TOPLEVELOBJECT(name,funcname) pISInterface->RemoveTopLevelObject(name);
#include "TopLevelObjects.h"
#undef TOPLEVELOBJECT
}
void ISXTesty::UnRegisterServices()
{
// shutdown our own services
// if (hISXTestyService)
// pISInterface->ShutdownService(this,hISXTestyService);
#define SERVICE(_name_,_callback_,_variable_) _variable_=pISInterface->ShutdownService(this,_variable_);
#include "Services.h"
#undef SERVICE
}
void __cdecl PulseService(bool Broadcast, unsigned int MSG, void *lpData)
{
if (MSG==PULSE_PULSE)
{
/*
* "OnPulse"
* This message is received by the extension before each frame is
* displayed by the game. This is the place to put any repeating
* tasks.
*/
}
}
void __cdecl MemoryService(bool Broadcast, unsigned int MSG, void *lpData)
{
// no messages are currently associated with this service (other than
// system messages such as client disconnect), so do nothing.
}
void __cdecl TriggerService(bool Broadcast, unsigned int MSG, void *lpData)
{
// no messages are currently associated with this service (other than
// system messages such as client disconnect), so do nothing.
}
void __cdecl SystemService(bool Broadcast, unsigned int MSG, void *lpData)
{
if (MSG==SYSTEMSERVICE_DIAGNOSTICS)
{
// Diagnostics sample
/*
FILE *file=(FILE*)lpData;
fprintf(file,"ISXTesty version %s\n",EXTENSION_VERSION);
fprintf(file,"------------------------------------\n",EXTENSION_VERSION);
fprintf(file,"Any ISXTesty diagnostic information here\n");
fprintf(file,"\n");// extra spacing for making the crash log look nice
/**/
}
}
void __cdecl HTTPService(bool Broadcast, unsigned int MSG, void *lpData)
{
switch(MSG)
{
#define pReq ((HttpFile*)lpData)
case HTTPSERVICE_FAILURE:
// HTTP request failed to retrieve document
printf("ISXTesty URL %s failed",pReq->URL);
break;
case HTTPSERVICE_SUCCESS:
// HTTP request successfully retrieved document
printf("ISXTesty URL %s -- %d bytes",pReq->URL,pReq->Size);
// Retrieved data buffer is pReq->pBuffer and is null-terminated
break;
#undef pReq
}
}