From b4a0fccf426e0e1ff68bad868230b0dfa3ded180 Mon Sep 17 00:00:00 2001 From: Robert MacGregor Date: Sun, 16 Nov 2014 17:53:23 -0500 Subject: [PATCH] Updated TCPObject code to use the STL though it needs bug fixes; added Bahke's contributions --- .../TSExtension/include/DXAPI/DXAPI.h | 1 - .../TSExtension/include/DXAPI/GameBase.h | 9 +- .../include/DXAPI/GameConnection.h | 3 +- .../TSExtension/include/DXAPI/NetConnection.h | 53 ++++ .../TSExtension/include/DXConCmds.h | 5 +- .../TSExtension/include/LinkerAPI.h | 5 +- .../TSExtension/source/DXAPI/DXAPI.cpp | 1 + .../TSExtension/source/DXAPI/GameBase.cpp | 2 + .../source/DXAPI/NetConnection.cpp | 29 +- .../TSExtension/source/DXAPI/SimObject.cpp | 2 +- .../TSExtension/source/DXConCmds.cpp | 53 +++- .../TSExtension/source/DXTCPObjects.cpp | 273 +++++++----------- .../TSExtension/source/LinkerAPI.cpp | 7 + .../TSExtension/source/dllmain.cpp | 4 +- 14 files changed, 260 insertions(+), 187 deletions(-) diff --git a/Mod Sources/TSExtension/TSExtension/include/DXAPI/DXAPI.h b/Mod Sources/TSExtension/TSExtension/include/DXAPI/DXAPI.h index 72391c4..93105e1 100644 --- a/Mod Sources/TSExtension/TSExtension/include/DXAPI/DXAPI.h +++ b/Mod Sources/TSExtension/TSExtension/include/DXAPI/DXAPI.h @@ -38,7 +38,6 @@ namespace DX typedef void* UnresolvedObject; const char *GetModPaths(void); - bool IsFile(const char *filename); bool GetRelativePath(const char *filename, char *ret, int buffer_length); diff --git a/Mod Sources/TSExtension/TSExtension/include/DXAPI/GameBase.h b/Mod Sources/TSExtension/TSExtension/include/DXAPI/GameBase.h index 3a9be4a..a0a5d4e 100644 --- a/Mod Sources/TSExtension/TSExtension/include/DXAPI/GameBase.h +++ b/Mod Sources/TSExtension/TSExtension/include/DXAPI/GameBase.h @@ -1,12 +1,19 @@ #pragma once #include - + enum GameBaseMasks { + InitialUpdateMask = 1 << 0, + DataBlockMask = 1 << 1, + ExtendedInfoMask = 1 << 2, + NextFreeMask = ExtendedInfoMask << 1 + }; namespace DX { class GameBase : public SceneObject { + public: GameBase(unsigned int obj); + void setProcessTicks(bool proc); }; } // End NameSpace DX diff --git a/Mod Sources/TSExtension/TSExtension/include/DXAPI/GameConnection.h b/Mod Sources/TSExtension/TSExtension/include/DXAPI/GameConnection.h index 9dbfc35..a05bb7f 100644 --- a/Mod Sources/TSExtension/TSExtension/include/DXAPI/GameConnection.h +++ b/Mod Sources/TSExtension/TSExtension/include/DXAPI/GameConnection.h @@ -2,7 +2,7 @@ #include #include - +#include #include namespace DX @@ -13,5 +13,6 @@ namespace DX GameConnection(unsigned int obj); ShapeBase getControlObject(void); + }; } // End NameSpace DX diff --git a/Mod Sources/TSExtension/TSExtension/include/DXAPI/NetConnection.h b/Mod Sources/TSExtension/TSExtension/include/DXAPI/NetConnection.h index f7ffb9b..73fe542 100644 --- a/Mod Sources/TSExtension/TSExtension/include/DXAPI/NetConnection.h +++ b/Mod Sources/TSExtension/TSExtension/include/DXAPI/NetConnection.h @@ -2,6 +2,10 @@ #include #include +#include +#include + +struct GhostInfo; namespace DX { @@ -9,5 +13,54 @@ namespace DX { public: NetConnection(unsigned int obj); + S32 getGhostIndex(NetObject *obj); + GhostInfo * mGhostRefs; }; } // End NameSpace DX + +struct GhostRef; +struct GhostInfo +{ + public: // required for MSVC + + // NOTE: + // if the size of this structure changes, the + // NetConnection::getGhostIndex function MUST be changed + // to reflect. + + DX::NetObject *obj; // the real object + U32 updateMask; // 32 bits of object info + GhostRef *updateChain; // chain of updates for this object in packets + GhostInfo *nextObjectRef; // next ghost ref for this object (another connection) + + GhostInfo *prevObjectRef; // prev ghost ref for this object + DX::NetConnection *connection; + GhostInfo *nextLookupInfo; + U32 updateSkipCount; + + U32 flags; + F32 priority; + U32 index; + U32 arrayIndex; + + enum Flags + { + Valid = BIT(0), + InScope = BIT(1), + ScopeAlways = BIT(2), + NotYetGhosted = BIT(3), + Ghosting = BIT(4), + KillGhost = BIT(5), + KillingGhost = BIT(6), + ScopedEvent = BIT(7), + ScopeLocalAlways = BIT(8), + }; +}; + struct GhostRef + { + U32 mask; + U32 ghostInfoFlags; + GhostInfo *ghost; + GhostRef *nextRef; + GhostRef *nextUpdateChain; + }; diff --git a/Mod Sources/TSExtension/TSExtension/include/DXConCmds.h b/Mod Sources/TSExtension/TSExtension/include/DXConCmds.h index 14685f7..f82f343 100644 --- a/Mod Sources/TSExtension/TSExtension/include/DXConCmds.h +++ b/Mod Sources/TSExtension/TSExtension/include/DXConCmds.h @@ -22,7 +22,7 @@ bool conPlayerGetJumpingState(Linker::SimObject *obj, S32 argc, const char* argv bool conPlayerGetJettingState(Linker::SimObject *obj, S32 argc, const char* argv[]); bool conGameConnectionSetHeatLevel(Linker::SimObject *obj, S32 argc, const char *argv[]); - +bool conSetProcessTicks(Linker::SimObject *obj, S32 argc, const char* argv[]) ; // GrenadeProjectile Commands ------------------------ const char* conGrenadeProjectileGetPosition(Linker::SimObject *obj, S32 argc, const char* argv[]); const char* conGrenadeProjectileGetVelocity(Linker::SimObject *obj, S32 argc, const char* argv[]); @@ -50,6 +50,9 @@ const char *conBinaryObjectGetBufferPointer(Linker::SimObject *obj, S32 argc, co bool conBinaryObjectClose(Linker::SimObject *obj, S32 argc, const char *argv[]); bool conBinaryObjectSave(Linker::SimObject *obj, S32 argc, const char *argv[]); +// Network Commands --------------------------------- +S32 conGetGhostIndex(Linker::SimObject *obj, S32 argc, const char* argv[]); +bool conForceUpdate(Linker::SimObject *obj, S32 argc, const char* argv[]); // General Commands --------------------------------- const char* conSprintf(Linker::SimObject *obj, S32 argc, const char* argv[]); bool conTSExtensionUpdate(Linker::SimObject *obj, S32 argc, const char *argv[]); \ No newline at end of file diff --git a/Mod Sources/TSExtension/TSExtension/include/LinkerAPI.h b/Mod Sources/TSExtension/TSExtension/include/LinkerAPI.h index 148259c..4bd5d8d 100644 --- a/Mod Sources/TSExtension/TSExtension/include/LinkerAPI.h +++ b/Mod Sources/TSExtension/TSExtension/include/LinkerAPI.h @@ -83,9 +83,12 @@ void GuiTSCtrl_project(GuiTSCtrl *obj, const Linker::Point3F &pt, Linker::Point3 namespace Sim { extern Linker::SimObject* (*findObject)(U32 id); + extern Linker::SimObject* (*findObjectc)(const char* name); } //console +#define BIT(x) (1 << (x)) + typedef const char * (*StringCallback)(Linker::SimObject *obj, S32 argc, const char *argv[]); typedef S32 (*IntCallback)(Linker::SimObject *obj, S32 argc, const char *argv[]); @@ -102,7 +105,7 @@ extern char * (*getReturnBuffer)(U32 bufferSize); extern void (*addMethodB)(const char *nsName, const char *name, BoolCallback cb, const char *usage, S32 minArgs, S32 maxArgs); extern void (*addMethodS)(const char *nsName, const char *name, StringCallback cb, const char *usage, S32 minArgs, S32 maxArgs); - +extern void (*addMethodI)(const char *nsName, const char *name, IntCallback cb, const char *usage, S32 minArgs, S32 maxArgs); extern bool (*addVariable)(const char *name, S32 t, void *dp); extern void (*printf)(const char* fmt,...); diff --git a/Mod Sources/TSExtension/TSExtension/source/DXAPI/DXAPI.cpp b/Mod Sources/TSExtension/TSExtension/source/DXAPI/DXAPI.cpp index e97ccd6..e68e788 100644 --- a/Mod Sources/TSExtension/TSExtension/source/DXAPI/DXAPI.cpp +++ b/Mod Sources/TSExtension/TSExtension/source/DXAPI/DXAPI.cpp @@ -19,6 +19,7 @@ namespace DX { + const char *GetModPaths(void) { int pointer = *(int*)0x9E8690; diff --git a/Mod Sources/TSExtension/TSExtension/source/DXAPI/GameBase.cpp b/Mod Sources/TSExtension/TSExtension/source/DXAPI/GameBase.cpp index 1c1bad9..9feba1b 100644 --- a/Mod Sources/TSExtension/TSExtension/source/DXAPI/GameBase.cpp +++ b/Mod Sources/TSExtension/TSExtension/source/DXAPI/GameBase.cpp @@ -5,4 +5,6 @@ namespace DX GameBase::GameBase(unsigned int obj) : SceneObject(obj) { } + + } // End NameSpace DX \ No newline at end of file diff --git a/Mod Sources/TSExtension/TSExtension/source/DXAPI/NetConnection.cpp b/Mod Sources/TSExtension/TSExtension/source/DXAPI/NetConnection.cpp index 5943c89..698e21b 100644 --- a/Mod Sources/TSExtension/TSExtension/source/DXAPI/NetConnection.cpp +++ b/Mod Sources/TSExtension/TSExtension/source/DXAPI/NetConnection.cpp @@ -1,8 +1,29 @@ #include - +#include +#include namespace DX { - NetConnection::NetConnection(unsigned int obj) : SimObject(obj) - { + S32 NetConnection::getGhostIndex(NetObject *obj) { + unsigned int object_ptr = (unsigned int)obj->base_pointer_value; + unsigned int my_ptr = this->base_pointer_value-0xA0; + unsigned int ghostid=0; + unsigned int function=0x584FB0; + __asm + { + mov ecx,my_ptr + mov edx,object_ptr + push edx + call function + mov ghostid, eax + } + return ghostid; } -} \ No newline at end of file + + NetConnection::NetConnection(unsigned int obj) : SimObject(obj) + + { + this->mGhostRefs = (GhostInfo *)this->base_pointer_value-0xA0+0x8210; + } + +} + diff --git a/Mod Sources/TSExtension/TSExtension/source/DXAPI/SimObject.cpp b/Mod Sources/TSExtension/TSExtension/source/DXAPI/SimObject.cpp index 89c54f8..ab5e7ec 100644 --- a/Mod Sources/TSExtension/TSExtension/source/DXAPI/SimObject.cpp +++ b/Mod Sources/TSExtension/TSExtension/source/DXAPI/SimObject.cpp @@ -9,7 +9,7 @@ namespace DX SimObject::SimObject(unsigned int obj) : identifier(*(unsigned int*)(obj + 32)), base_pointer_value(obj) { - } + } void SimObject::deleteObject(void) { diff --git a/Mod Sources/TSExtension/TSExtension/source/DXConCmds.cpp b/Mod Sources/TSExtension/TSExtension/source/DXConCmds.cpp index c5adc2c..60e46a6 100644 --- a/Mod Sources/TSExtension/TSExtension/source/DXConCmds.cpp +++ b/Mod Sources/TSExtension/TSExtension/source/DXConCmds.cpp @@ -19,7 +19,6 @@ bool conPlayerGetJumpingState(Linker::SimObject *obj, S32 argc, const char* argv return operand.is_jumping; } - bool conPlayerGetJettingState(Linker::SimObject *obj, S32 argc, const char* argv[]) { DX::Player operand = DX::Player((unsigned int)obj); @@ -55,7 +54,59 @@ bool conProjectileMakeNerf(Linker::SimObject *obj, S32 argc, const char* argv[]) return true; } +bool conForceUpdate(Linker::SimObject *obj, S32 argc, const char* argv[]) { + DX::NetConnection conn = DX::NetConnection((unsigned int)obj); + DX::NetObject netobj = DX::NetObject((unsigned int)Sim::findObjectc(argv[2])); + if (netobj.base_pointer_value!=0) { + S32 index = conn.getGhostIndex(&netobj); + if (index > 0) { + conn.mGhostRefs[index].updateMask=conn.mGhostRefs[index].updateMask | GameBaseMasks::InitialUpdateMask; + } + return 1; + } + else + { + return 0; + } +} +S32 conGetGhostIndex(Linker::SimObject *obj, S32 argc, const char* argv[]) { + DX::NetConnection conn = DX::NetConnection((unsigned int)obj); + DX::NetObject netobj = DX::NetObject((unsigned int)Sim::findObjectc(argv[2])); + if (netobj.base_pointer_value!=0) { + S32 index = conn.getGhostIndex(&netobj); + return index; + } else { + return (unsigned int)Sim::findObjectc(argv[1]); + } + //conn.mGhostRefs[index].updateMask=conn.mGhostRefs[index].updateMask | GameBaseMasks::InitialUpdateMask; +} +bool conSetProcessTicks(Linker::SimObject *obj, S32 argc, const char* argv[]) { + unsigned int result_ptr = 0; + unsigned int my_ptr = (unsigned int) obj; + if (atoi(argv[2])==1) { + __asm + { + mov eax, my_ptr; + add eax, 0x264; + mov ebx,eax + mov al, 1 + mov [ebx],al + + } + } else { + __asm + { + mov eax, my_ptr; + add eax, 0x264; + mov ebx,eax + mov al, 0 + mov [ebx],al + + } + } + +} const char* conGrenadeProjectileGetPosition(Linker::SimObject *obj, S32 argc, const char* argv[]) { char result[256]; diff --git a/Mod Sources/TSExtension/TSExtension/source/DXTCPObjects.cpp b/Mod Sources/TSExtension/TSExtension/source/DXTCPObjects.cpp index 5dde056..0a2a0a2 100644 --- a/Mod Sources/TSExtension/TSExtension/source/DXTCPObjects.cpp +++ b/Mod Sources/TSExtension/TSExtension/source/DXTCPObjects.cpp @@ -1,15 +1,21 @@ +#include +#include + +#include +#include +#include +#include + #include #include -#include -#include #define TCPOBJECT_MAXCOUNT 256 #define TCPOBJECT_BUFFERSIZE 256 #define TCPOBJECT_SENDQUEUELENGTH 64 // Number of elements -static unsigned int TSEXTENSION_RUNNINGTCPOBJECTCOUNT = 0; -static DX::TCPObject *TSEXTENSION_RUNNINGTCPOBJECTS[TCPOBJECT_MAXCOUNT]; +//! A mapping of object ID's to DX::TCPObject instance pointers. +static std::map> sRunningTCPObjects; // Since TS wants function call arguments to be of type char*, we use this // helper function to painlessly pass in unsigned int arguments for things @@ -23,28 +29,13 @@ __forceinline static char *S32ToCharPtr(unsigned int in) } // Also a helper function to return the status of a socket -static bool DXTCP_GetSocketStatus(SOCKET sock) +static unsigned int DXTCP_GetSocketTime(SOCKET sock) { - fd_set sockets; - sockets.fd_array[0] = sock; - sockets.fd_count = 1; - - // We don't want to do any waiting at all - timeval wait_time; - wait_time.tv_sec = 0; - wait_time.tv_usec = 0; + unsigned int optVal; + int optLen = sizeof(unsigned int); - return select(sock, &sockets, &sockets, NULL, &wait_time) != SOCKET_ERROR; -} - -inline DX::TCPObject *TCPObject_Find(unsigned int identifier) -{ - // Make sure it's in our list of objects - for (unsigned int iteration = 0; iteration < TSEXTENSION_RUNNINGTCPOBJECTCOUNT; iteration++) - if (TSEXTENSION_RUNNINGTCPOBJECTS[iteration]->identifier == identifier) - return TSEXTENSION_RUNNINGTCPOBJECTS[iteration]; - - return 0x00; + getsockopt(sock, SOL_SOCKET, SO_CONNECT_TIME, (char*)&optVal, &optLen); + return optVal; } typedef struct @@ -53,56 +44,42 @@ typedef struct unsigned int target_port; unsigned int buffer_length; - char *buffer; - - unsigned int message_count; - char *message_queue[TCPOBJECT_SENDQUEUELENGTH]; + std::set mOutgoingQueue; + std::string mIncomingBuffer; bool is_connected; SOCKET socket; } ConnectionInformation; - -inline bool TCPObject_Disconnect(unsigned int identifier) +inline void TCPObject_Disconnect(DX::TCPObject *obj) { - DX::TCPObject *obj = TCPObject_Find(identifier); - if (!obj) - return false; + ConnectionInformation *connectionInfo = (ConnectionInformation*)obj->state; - ConnectionInformation *connection = (ConnectionInformation*)obj->state; + if (connectionInfo->socket == 0) + { + closesocket(connectionInfo->socket); + connectionInfo->socket = 0; - closesocket(connection->socket); - connection->socket = 0; - - // Find us in the array - unsigned int target_index = 0; - for (unsigned int iteration = 0; iteration < TSEXTENSION_RUNNINGTCPOBJECTCOUNT; iteration++) - if (TSEXTENSION_RUNNINGTCPOBJECTS[iteration] == obj) - { - target_index = iteration; - break; - } - - // Fix the array - for (unsigned int iteration = target_index; iteration < TSEXTENSION_RUNNINGTCPOBJECTCOUNT; iteration++) - TSEXTENSION_RUNNINGTCPOBJECTS[iteration] = TSEXTENSION_RUNNINGTCPOBJECTS[iteration + 1]; - TSEXTENSION_RUNNINGTCPOBJECTCOUNT--; + Con::errorf(0, "Attempted to disconnect an already disconnected TCPObject - %u", obj->identifier); + return; + } obj->CallMethod("onDisconnect", 0); - return true; + delete connectionInfo; + + // Causes the ptr to our DX::TCPObject to deallocate + sRunningTCPObjects.erase(obj->identifier); + + Con::errorf(0, "Processed Disconnect"); } const char* conTCPObjectConnect(Linker::SimObject *obj, S32 argc, const char *argv[]) { - DX::TCPObject *operand = TCPObject_Find(atoi(argv[1])); - if (operand) - { - TCPObject_Disconnect(operand->identifier); - delete operand; - } + if (sRunningTCPObjects.count(obj->mId) >= 1) + TCPObject_Disconnect(sRunningTCPObjects[obj->mId].get()); - operand = new DX::TCPObject((unsigned int)obj); + DX::TCPObject *operand = new DX::TCPObject((unsigned int)obj); // Copy the hostname over char *desired_hostname = (char*)malloc(strlen(argv[2]) + 1); @@ -111,10 +88,8 @@ const char* conTCPObjectConnect(Linker::SimObject *obj, S32 argc, const char *ar // Create the connection info ConnectionInformation *connection = new ConnectionInformation; connection->target_hostname = desired_hostname; - connection->buffer = 0x00; connection->buffer_length = 0; connection->is_connected = false; - connection->message_count = 0; connection->socket = 0; // Hack: Store the Ptr to our connection information struct in the old unused state value @@ -182,20 +157,18 @@ const char* conTCPObjectConnect(Linker::SimObject *obj, S32 argc, const char *ar u_long imode = 1; ioctlsocket(connection->socket, FIONBIO, &imode); - // Stick us in the TCPObject array - TSEXTENSION_RUNNINGTCPOBJECTS[TSEXTENSION_RUNNINGTCPOBJECTCOUNT] = operand; - TSEXTENSION_RUNNINGTCPOBJECTCOUNT++; + sRunningTCPObjects[obj->mId] = std::unique_ptr(operand); // Attempt the Connection connect(connection->socket, (SOCKADDR*)&target_host, sizeof(target_host)); - if (DXTCP_GetSocketStatus(connection->socket) == SOCKET_ERROR) + + if (getsockopt(connection->socket, SOL_SOCKET, SO_ERROR, NULL, NULL) < 0) { operand->CallMethod("onConnectFailed", 2, S32ToCharPtr(3), S32ToCharPtr(WSAGetLastError())); return "CANNOT_CONNECT"; } else { - connection->is_connected = true; operand->CallMethod("onConnected", 0); return "SUCCESS"; } @@ -207,25 +180,18 @@ bool conTCPObjectSend(Linker::SimObject *obj, S32 argc, const char *argv[]) { Con::errorf(0, "Should Send? - SimID %s", argv[1]); - if (!TCPObject_Find(atoi(argv[1]))) + if (sRunningTCPObjects.count(obj->mId) == 0) return false; - DX::TCPObject operand((unsigned int)obj); - ConnectionInformation *connection = (ConnectionInformation*)operand.state; + DX::TCPObject *operand = sRunningTCPObjects[obj->mId].get(); + ConnectionInformation *connection = (ConnectionInformation*)operand->state; // Since we can be attempting to send data before we're connected, we'll just queue // the data here and send it all in our update function next call if (!connection->is_connected) Con::errorf(0, "Attempted to send before connected."); - // Tribes 2 probably deallocates the memory associated with the arguments at some point - // so we'll copy the send payload into an independent chunk of memory - char *send_payload = new char[strlen(argv[2]) + 1]; - memset(send_payload, 0x00, strlen(argv[2]) + 1); - memcpy(send_payload, argv[2], strlen(argv[2]) + 1); - - connection->message_queue[connection->message_count] = send_payload; - connection->message_count++; + connection->mOutgoingQueue.insert(connection->mOutgoingQueue.end(), argv[2]); Con::errorf(0,"Queued data: %s", argv[2]); return true; @@ -233,7 +199,11 @@ bool conTCPObjectSend(Linker::SimObject *obj, S32 argc, const char *argv[]) bool conTCPObjectDisconnect(Linker::SimObject *obj, S32 argc, const char *argv[]) { - return TCPObject_Disconnect(atoi(argv[1])); + if (sRunningTCPObjects.count(obj->mId) == 0) + return false; + + TCPObject_Disconnect(sRunningTCPObjects[obj->mId].get()); + return true; } bool conTSExtensionUpdate(Linker::SimObject *obj, S32 argc, const char *argv[]) @@ -242,36 +212,36 @@ bool conTSExtensionUpdate(Linker::SimObject *obj, S32 argc, const char *argv[]) static char *incoming_buffer = new char[TCPOBJECT_BUFFERSIZE]; // List of objects to D/C - unsigned int disconnected_object_count = 0; - static DX::TCPObject **disconnected_objects = (DX::TCPObject**)malloc(sizeof(DX::TCPObject*) * TCPOBJECT_MAXCOUNT); + std::set> disconnections; - for (unsigned int iteration = 0; iteration < TSEXTENSION_RUNNINGTCPOBJECTCOUNT; iteration++) + for (std::map>::iterator it = sRunningTCPObjects.begin(); it != sRunningTCPObjects.end(); it++) { - // Zero out the incoming buffer per iteration memset(incoming_buffer, 0x00, TCPOBJECT_BUFFERSIZE); - DX::TCPObject *current_connection = TSEXTENSION_RUNNINGTCPOBJECTS[iteration]; - ConnectionInformation *connection_information = (ConnectionInformation*)current_connection->state; + const std::unique_ptr ¤tConnection = (*it).second; - // FIXME: ::onConnect is never called if is where we finally realize we're connected - // Check if we're ready to be performing network operations - if (DXTCP_GetSocketStatus(connection_information->socket)) - connection_information->is_connected = true; - else + ConnectionInformation *connectionInfo = (ConnectionInformation*)currentConnection.get()->state; + + const int socketTime = DXTCP_GetSocketTime(connectionInfo->socket); + if (socketTime >= 1 && !connectionInfo->is_connected) { - Con::errorf(0,"Socket status error!"); - disconnected_objects[disconnected_object_count] = current_connection; - disconnected_object_count++; - break; + connectionInfo->is_connected = true; + currentConnection.get()->CallMethod("onConnected", 0); } // Process the send queue first bool connection_is_ready = true; - if (connection_information->is_connected && connection_information->message_count != 0) - for (unsigned int queue_iteration = 0; queue_iteration < connection_information->message_count; queue_iteration++) - if (send(connection_information->socket, connection_information->message_queue[queue_iteration], strlen(connection_information->message_queue[queue_iteration]), 0) == SOCKET_ERROR) + if (connectionInfo->is_connected) + { + for (std::set::iterator it = connectionInfo->mOutgoingQueue.begin(); it != connectionInfo->mOutgoingQueue.end(); it++) + { + const std::string ¤tMessage = *it; + Con::errorf(0, "Processing Send: %s", currentMessage.c_str()); + + if (send(connectionInfo->socket, currentMessage.c_str(), currentMessage.length(), 0) == SOCKET_ERROR) { int wsa_error = WSAGetLastError(); + // We're not ready yet, just break and we should eventually be ready if (wsa_error == WSAEWOULDBLOCK) { @@ -279,122 +249,75 @@ bool conTSExtensionUpdate(Linker::SimObject *obj, S32 argc, const char *argv[]) break; } - connection_information->is_connected = false; - disconnected_objects[disconnected_object_count] = current_connection; - disconnected_object_count++; + connectionInfo->is_connected = false; + disconnections.insert(disconnections.end(), currentConnection.get()); + Con::errorf(0,"Got a send error! SimID: %u - Error %u", currentConnection->identifier, wsa_error); - Con::errorf(0,"Got a send error! SimID: %u - Error %u", current_connection->identifier, wsa_error); break; } - else - delete[] connection_information->message_queue[queue_iteration]; - + } + + // Empty the queue + connectionInfo->mOutgoingQueue.clear(); + } + // We can break if the connection was never made yet or if there was an error processing the message queue - if (!connection_information->is_connected || !connection_is_ready) - break; + if (!connectionInfo->is_connected || !connection_is_ready) + continue; // FIXME: Under send() error conditions we can't deallocate all of the associated memory - connection_information->message_count = 0; - unsigned int data_length = recv(connection_information->socket, incoming_buffer, TCPOBJECT_BUFFERSIZE, 0); + unsigned int data_length = recv(connectionInfo->socket, incoming_buffer, TCPOBJECT_BUFFERSIZE, 0); int currentError = WSAGetLastError(); + + Con::errorf(0, "%u", DXTCP_GetSocketTime(connectionInfo->socket)); + if (currentError != WSAEWOULDBLOCK && currentError != 0) { - Con::errorf(0, "Got an error! %u - SimID %u", currentError, current_connection->identifier); - disconnected_objects[disconnected_object_count] = current_connection; - disconnected_object_count++; + Con::errorf(0, "Got an error! %u - SimID %u", currentError, currentConnection.get()->identifier); + + disconnections.insert(disconnections.end(), currentConnection.get()); } else if (data_length == 0) { Con::errorf(0, "Finished receiving?"); // Put us on the D/C list - disconnected_objects[disconnected_object_count] = current_connection; - disconnected_object_count++; + disconnections.insert(disconnections.end(), currentConnection.get()); - // Our actual buffer is +1 bytes in length, so will set the extra byte to 0x00 to ensure NULL termination - connection_information->buffer[connection_information->buffer_length] = 0x00; - - Con::errorf(0, "Stream Len: %u Bytes", connection_information->buffer_length); // Stream the data into ::onLine unsigned int current_start = 0; - for (unsigned int split_iteration = 0; split_iteration < connection_information->buffer_length; split_iteration++) + + for (unsigned int split_iteration = 0; split_iteration < connectionInfo->mIncomingBuffer.length(); split_iteration++) { - bool streaming_line = false; - if (connection_information->buffer[split_iteration] == '\n') // || split_iteration == connection_information->buffer_length - 1 + if (connectionInfo->mIncomingBuffer[split_iteration] == '\r') + connectionInfo->mIncomingBuffer[split_iteration] = ' '; + + if (connectionInfo->mIncomingBuffer[split_iteration] == '\n') // || split_iteration == connection_information->buffer_length - 1 { - connection_information->buffer[split_iteration] = 0x00; - streaming_line = true; - } - else if (split_iteration == connection_information->buffer_length - 1) - streaming_line = true; - - //unsigned int desired_length = (split_iteration - current_start); - - //if (desired_length == data_length) - // current_connection->TSCall("onLine", 1, connection_information->buffer); - //else - //{ - //if(split_iteration != connection_information->buffer_length - 1) - // connection_information->buffer[split_iteration] = 0x00; - - if (streaming_line) - { - // Time to be clever: Since T2 doesn't care what happens to the string after it's passed in, I'm not - // Bothering to allocate more memory for the results. I'm just going to manipulate it to appear as - // different lines but in reality they're all sourced from the same memory. - char *current_line = &connection_information->buffer[current_start]; - - Con::errorf(0, "Streamed: %s", current_line); - - // If we just have a blank line (a carriage return), replace it with the space character - if (strlen(current_line) == 1 && current_line[0] == 0xD) - current_line[0] = 0x20; + const std::string currentLine = connectionInfo->mIncomingBuffer.substr(current_start, split_iteration - current_start); current_start = split_iteration + 1; - current_connection->CallMethod("onLine", 1, current_line); + + Con::errorf(0, "Streaming: %s", currentLine.c_str()); + currentConnection.get()->CallMethod("onLine", 1, currentLine.c_str()); } } - - closesocket(connection_information->socket); - connection_information->socket = 0; - delete[] connection_information->buffer; } else if (data_length <= TCPOBJECT_BUFFERSIZE) { Con::errorf(0, "Received Data: %u", data_length); - // If our connection hasn't buffered anything yet - if (connection_information->buffer == 0x00) - { - // Allocate our memory with a +1 Byte Size (to ensure it's properly NULL terminated when we stream to ::onLine) - connection_information->buffer = new char[data_length + 1]; - memset(connection_information->buffer, 0x00, data_length + 1); - - connection_information->buffer_length = data_length; - memcpy(connection_information->buffer, incoming_buffer, data_length); - } - else - { - unsigned int new_buffer_length = data_length + connection_information->buffer_length; - char *new_buffer = new char[new_buffer_length + 1]; - memset(new_buffer, 0x00, new_buffer_length + 1); - - // Copy the two halves - memcpy(new_buffer, connection_information->buffer, connection_information->buffer_length); - memcpy(&new_buffer[connection_information->buffer_length], incoming_buffer, data_length); - - connection_information->buffer = new_buffer; - connection_information->buffer_length = new_buffer_length; - } + connectionInfo->mIncomingBuffer += incoming_buffer; } } // Process Disconnect list - for (unsigned int iteration = 0; iteration < disconnected_object_count; iteration++) - TCPObject_Disconnect(disconnected_objects[iteration]->identifier); + for (std::set>::iterator it = disconnections.begin(); it != disconnections.end(); it++) + TCPObject_Disconnect((*it).get()); return true; + } bool conHTTPObjectDoNothing(Linker::SimObject *obj, S32 argc, const char *argv[]) diff --git a/Mod Sources/TSExtension/TSExtension/source/LinkerAPI.cpp b/Mod Sources/TSExtension/TSExtension/source/LinkerAPI.cpp index e7409fe..aadc7c0 100644 --- a/Mod Sources/TSExtension/TSExtension/source/LinkerAPI.cpp +++ b/Mod Sources/TSExtension/TSExtension/source/LinkerAPI.cpp @@ -7,6 +7,9 @@ namespace Sim { Linker::SimObject* (*findObject)(U32 id) = (Linker::SimObject* (_cdecl *)(U32 id) ) 0x439550; + Linker::SimObject* (*findObjectc)(const char* name) = + (Linker::SimObject* (_cdecl *)(const char* name) ) + 0x439450; } //hackey way to do member functions, .... @@ -31,6 +34,10 @@ char* (*getReturnBuffer)(U32 bufferSize) = (char *(__cdecl *)(U32)) 0x42caa0; +void (*addMethodI)(const char *nsName, const char *name, IntCallback cb, const char *usage, S32 minArgs, S32 maxArgs) = + (void (__cdecl *)(const char *, const char *,IntCallback,const char *,S32,S32)) + 0x426490; + void (*addMethodB)(const char *nsName, const char *name, BoolCallback cb, const char *usage, S32 minArgs, S32 maxArgs) = (void (__cdecl *)(const char *, const char *,BoolCallback,const char *,S32,S32)) 0x426510; diff --git a/Mod Sources/TSExtension/TSExtension/source/dllmain.cpp b/Mod Sources/TSExtension/TSExtension/source/dllmain.cpp index c4a494f..6cf8522 100644 --- a/Mod Sources/TSExtension/TSExtension/source/dllmain.cpp +++ b/Mod Sources/TSExtension/TSExtension/source/dllmain.cpp @@ -36,6 +36,7 @@ extern "C" Con::addMethodB("GameConnection", "setheat", &conGameConnectionSetHeatLevel,"Sets the heat level", 3, 3); Con::addMethodB("GrenadeProjectile", "explode", &conProjectileExplode,"Explodes the given projectile", 5, 5); + Con::addMethodB("GameBase","setProcessTicks",&conSetProcessTicks,"Sets the flag for processing ticks or not", 3, 3); Con::addMethodB("Projectile", "explode", &conProjectileExplode,"Explodes the given projectile", 5, 5); Con::addMethodS("GrenadeProjectile", "getposition", &conGrenadeProjectileGetPosition,"Accurately gets the position of the GrenadeProjectile", 2, 2); @@ -64,7 +65,8 @@ extern "C" Con::addMethodS("BinaryObject", "getbufferlength", &conBinaryObjectGetBufferLength, "Returns the length of the buffer", 2, 2); Con::addMethodS("BinaryObject", "getbufferpointer", &conBinaryObjectGetBufferPointer, "Returns the buffer pointer", 2, 2); Con::addMethodB("BinaryObject", "close", &conBinaryObjectClose, "Closes the binary object", 2, 2); - + Con::addMethodI("NetConnection","getGhostIndex", &conGetGhostIndex, "Gets a ghost index for an object id", 3, 3); + Con::addMethodB("NetConnection","conForceUpdate", &conForceUpdate,"Forces an initial update for an object id", 3, 3); // General Con::addMethodS(NULL, "sprintf", &conSprintf,"Formats a string. See the C sprintf.", 2, 20); Con::addMethodB(NULL, "tsExtensionUpdate", &conTSExtensionUpdate,"Updates the TSExtension.", 1, 1);