"Unity Battle Space" VBS Plugin DLL |
This is the VBS plugin DLL portion of the Unity Battle Space project. It is written in C++ in conjunction with the SDL_Net API (networking portion of the SDL API) which allowed me to do TCP/IP programming much more easily. The VBS plugin client parses server commands and then constructs VBS script commands as strings to be sent in game (and vice versa). The C# portions of this project can be found HERE in the C# section. |
vbsplugin.h |
#ifndef _VBS_PLUGIN_H__ #define _VBS_PLUGIN_H__ #define VBSPLUGIN_EXPORT __declspec(dllexport) VBSPLUGIN_EXPORT void WINAPI RegisterHWND(void *hwnd, void *hins); //handlw to vbs2 window instance in the event of any graphical interface is implemented via plugin VBSPLUGIN_EXPORT void WINAPI RegisterCommandFnc(void *executeCommandFnc); //passes the function the dll must call to execute vbs2 script commands VBSPLUGIN_EXPORT void WINAPI OnSimulationStep(float deltaT); //called each frame, try not to do too many intensive things in this method as it will effect framerate VBSPLUGIN_EXPORT const char* WINAPI PluginFunction(const char *input); //gets called when the vbs2 function of the same name is called #endif |
VBSPlugin.cpp |
//no idea what this does but needed for sdl i think///////////////////////// #if 0 #!/bin/sh gcc -Wall `sdl-config --cflags` tcpc.c -o tcpc `sdl-config --libs` -lSDL_net exit #endif ////////////////////////////////////////////////////////////////////////////// //defs #define BUFFER_SIZE 512 //libs #include <windows.h> //needed for a good chunk of windows specific methods #include <string.h> //string object #include <iostream> //needed for std:: #include <exception> //exception object #include <sstream> //string stream object #include <string> //string object #include <fstream> //file io #include "VBSPlugin.h" //our header (all it does is import dll methods) #include "SDL_net.h" //sdl networking //prototypes std::string checkServer(Uint16 _port, std::string _sHost); //check the server for instruction void updateServer(Uint16 _port, std::string _sHost, std::string _strCommand); //send command to server //command function declaration typedef int (WINAPI *ExecuteCommandType) (const char *command, char *result, int resultLength); //command function definition ExecuteCommandType ExecuteCommand=NULL; //this will hold callback functions passed from vbs2 during RegisterCommandFunc VBSPLUGIN_EXPORT void WINAPI RegisterCommandFnc(void *executeCommandFnc) { ExecuteCommand=(ExecuteCommandType)executeCommandFnc; } //shows how executeCommandFnc gets stored as ExecuteCommand which is used to invoke script commands in vbs2 VBSPLUGIN_EXPORT void WINAPI OnSimulationStep(float deltaT) { ExecuteCommand("_ret=pluginFunction [\"VBSPlugin\", applicationState select 1]", NULL, 0); //ask vbs for it's application state ExecuteCommand("_ret=pluginFunction [\"VBSPlugin\", getDir (vehicle player)]", NULL, 0); //get hull rotation from vbs } /*example, in vbs2 the following script command: ret=pluginFunction["PLUGINNAME", "text or value"] -the "PLUGINNAME" is the name of the plugin without ".dll" -the "text or value" is passed as const char *input which is the argument for the cpp function PluginFunction -it is then parsed as necessary, appropriate operations made based up on it, and the resulting command to be sent back to vbs is returned to the ret var in the vbs2 script.*/ VBSPLUGIN_EXPORT const char* WINAPI PluginFunction(const char *input) { try { std::string strInput=input; //place char array into string if (strInput=="MISSION") { std::string strResponse=checkServer(8002, "127.0.0.1"); if (strResponse!="neg") {ExecuteCommand(strResponse.c_str(), NULL, 0);} } //if the input is numeric else if (strInput[0]=='0' || strInput[0]=='1' || strInput[0]=='2' || strInput[0]=='3' || strInput[0]=='4' || strInput[0]=='5' || strInput[0]=='6' || strInput[0]=='7' || strInput[0]=='8' || strInput[0]=='9') { updateServer(8003, "127.0.0.1", "SERVER set hullRot "+strInput); //give the server the hull rot } static const char result[]="[1.0, 3.75]"; //place something in the output (presently these values are meaningless) return result; //return it to vbs2 } catch (std::exception &e) { //std::string except=e.what(); //OutputDebugString(except.c_str()); } } BOOL WINAPI DllMain(HINSTANCE hDll, DWORD fdwReason, LPVOID lpvReserved) //main function { switch(fdwReason) { case DLL_PROCESS_ATTACH: OutputDebugString("Called DllMain with DLL PROCESS ATTACH\n"); break; case DLL_PROCESS_DETACH: OutputDebugString("Called DllMain with DLL PROCESS DETACH\n"); break; case DLL_THREAD_ATTACH: OutputDebugString("Called DllMain with DLL THREAD ATTACH\n"); break; case DLL_THREAD_DETACH: OutputDebugString("Called DllMain with DLL THREAD DETACH\n"); break; default: break; } return TRUE; } std::string checkServer(Uint16 _port, std::string _sHost) //check server for instruction { if (SDLNet_Init() < 0) //throw a fit if sdl networking doesn't initialize { std::stringstream ssException; ssException << "checkServer(Uint16, std::string) -- SDLNet_Init() error: " << SDLNet_GetError(); throw std::exception(ssException.str().c_str()); } IPaddress ip; //holds ip addy TCPsocket sd; //holds socket descriptor short int len; //length of message string char buffer[15]; //holds outgoing message char receiveBuffer[BUFFER_SIZE]; //receive buffer std::string strSend="what about now?"; //server query string std::string strReceive=""; //holds message from server if (SDLNet_ResolveHost(&ip, _sHost.c_str(), _port)) //throw a fit if we can't resolve our host { std::stringstream ssException; ssException << "checkServer(Uint16, std::string) -- SDLNet_ResolveHost() error: " << SDLNet_GetError(); throw std::exception(ssException.str().c_str()); } if (!(sd = SDLNet_TCP_Open(&ip))) //throw a fit if we can't open a connection with the server { std::stringstream ssException; ssException << "checkServer(Uint16, std::string) -- SDLNet_TCP_OPEN() error: " << SDLNet_GetError(); throw std::exception(ssException.str().c_str()); } for (unsigned short iClean=0; iClean<15; iClean++) {buffer[iClean]=' ';} //init buffer for (unsigned short iString=0; iString<strSend.length(); iString++) {buffer[iString]=strSend[iString];} //dump query string into buffer len=strlen(buffer); //set length of string if (SDLNet_TCP_Send(sd, (void *)buffer, len)<len) //send message to server and throw a fit if we can't { std::stringstream ssException; ssException << "checkServer(Uint16, std::string) -- SDLNet_TCP_SEND() error: " << SDLNet_GetError(); throw std::exception(ssException.str().c_str()); } for (unsigned short iBuffer=0; iBuffer<BUFFER_SIZE; iBuffer++) {receiveBuffer[iBuffer]=' ';} //clean receive buffer if (SDLNet_TCP_Recv(sd, receiveBuffer, BUFFER_SIZE) > 0) //grab server response { for (unsigned short iBuffer=0; iBuffer<BUFFER_SIZE; iBuffer++) //loop through what we got { if (receiveBuffer[iBuffer]!='~') {strReceive+=receiveBuffer[iBuffer];} //append to receive string if not at end of received command else {iBuffer=9999;} //otherwise early exit of for loop } } SDLNet_TCP_Close(sd); //close connection SDLNet_Quit(); //shut down sdl networking return strReceive; } void updateServer(Uint16 _port, std::string _sHost, std::string _strCommand) //send command to server { if (SDLNet_Init() < 0) //throw a fit if sdl networking doesn't initialize { std::stringstream ssException; ssException << "updateServer(Uint16, std::string, std::string) -- SDLNet_Init() error: " << SDLNet_GetError(); throw std::exception(ssException.str().c_str()); } IPaddress ip; //holds ip addy TCPsocket sd; //holds socket descriptor short int len; //length of message string char buffer[BUFFER_SIZE]; //holds outgoing message char receiveBuffer[BUFFER_SIZE]; //receive buffer std::string strSend=_strCommand; //command to send to server std::string strReceive=""; //holds message from server if (SDLNet_ResolveHost(&ip, _sHost.c_str(), _port)) //throw a fit if we can't resolve our host { std::stringstream ssException; ssException << "updateServer(Uint16, std::string, std::string) -- SDLNet_ResolveHost() error: " << SDLNet_GetError(); throw std::exception(ssException.str().c_str()); } if (!(sd = SDLNet_TCP_Open(&ip))) //throw a fit if we can't open a connection with the server { std::stringstream ssException; ssException << "updateServer(Uint16, std::string, std::string) -- SDLNet_TCP_OPEN() error: " << SDLNet_GetError(); throw std::exception(ssException.str().c_str()); } for (unsigned short iClean=0; iClean<BUFFER_SIZE; iClean++) {buffer[iClean]=' ';} //init buffer for (unsigned short iString=0; iString<strSend.length(); iString++) {buffer[iString]=strSend[iString];} //dump command string into buffer len=strlen(buffer);//set length of string if (SDLNet_TCP_Send(sd, (void *)buffer, len)<len) //send message to server and throw a fit if we can't { std::stringstream ssException; ssException << "updateServer(Uint16, std::string, std::string) -- SDLNet_TCP_SEND() error: " << SDLNet_GetError(); throw std::exception(ssException.str().c_str()); } for (unsigned short iBuffer=0; iBuffer<BUFFER_SIZE; iBuffer++) {receiveBuffer[iBuffer]=' ';} //clean receive buffer if (SDLNet_TCP_Recv(sd, receiveBuffer, BUFFER_SIZE) > 0) //grab server response { for (unsigned short iBuffer=0; iBuffer<BUFFER_SIZE; iBuffer++) //loop through what we got { if (receiveBuffer[iBuffer]!='~') {strReceive+=receiveBuffer[iBuffer];} //append to receive string if not at end of received command else {iBuffer=9999;} //otherwise early exit of for loop } } SDLNet_TCP_Close(sd); //close connection SDLNet_Quit(); //shut down sdl networking //return strReceive; } |
^RETURN TO TOP^ |