Game Development Community

Transfering String Data from client to server and vice versa in C++

by Robert Fritzen · in Torque 3D Professional · 06/02/2013 (8:25 am) · 21 replies

The lengthy title pretty much asks it all.

Say I have some String data that I want to send from the client to the server, or from the server to the client. How would I go about doing this in C++ (Obviously easy in TS)?
Page «Previous 1 2
#1
06/03/2013 (4:13 am)
Robert, it's not too bad.

First you will need to create a netevent for the transfer, I reuse the same one for client->server and server->client communication.

class NetFetchInspectorDataBlocks_Event: public NetEvent
	{
	public:
		typedef NetEvent Parent;
		friend class NetInspectorEvent_Helper;
		DECLARE_CONOBJECT(NetFetchInspectorDataBlocks_Event);
	private:
		const char* mClassName;
		S32         mMenuID;
		const char* mPayload;
		bool        mFinished;

	public:
		NetFetchInspectorDataBlocks_Event(S32 argc=0, const char **argv=NULL, NetConnection *conn = NULL);
	private:
		NetFetchInspectorDataBlocks_Event(const char* classname,S32 menuid);
		NetFetchInspectorDataBlocks_Event(S32 menuid,const char* payload,bool finished,bool);
	public:
		~NetFetchInspectorDataBlocks_Event();
		virtual void pack(NetConnection* conn, BitStream *stream);
		virtual void write(NetConnection* conn, BitStream *bstream);
		virtual void unpack(NetConnection* conn, BitStream *stream);
		virtual void process(NetConnection *conn);
	};

The pack and unpack is normal, just pick a buffer size, I use 128 characters.

To cut a string up into pieces you can use this code

int BitSize = 128;
				int bits = mCeil((double)returnval.length()/(double)BitSize);
				for (int i = 0; i < bits; i++)
					{
					int length = BitSize;
					if ((length + (i * BitSize)) > returnval.length())
						length = returnval.length() - (i * BitSize);
					String sbit = returnval.substr( i * BitSize, length);
					//Do command back to client here.
					conn->postNetEvent(new NetFetchDataBlocks_Event(mPassedThis,mCtrlIdx,mPassedIndex,sbit.c_str(),false));
					}
				conn->postNetEvent(new NetFetchDataBlocks_Event(mPassedThis,mCtrlIdx,mPassedIndex,"",true));

So it sends a event for each part of the string and sends a empty string to mark the end of the transmission.

On the client, just append the string back together


TorqueScript function.
function clientcmdObjectBuilderGui_FinishcreateDataBlockType(%passedthis,%datablockstring,%ctrlIDX,%passedindex,%hasmore)
   {
   $clientcmdObjectBuilderGui_FinishcreateDataBlockType[%passedthis,%ctrlIDX] = 
         $clientcmdObjectBuilderGui_FinishcreateDataBlockType[%passedthis,%ctrlIDX] @ %datablockstring;      
   if (!(%dbstring $= ""))
      return;
   for (%i =0; %i< getWordCount($clientcmdObjectBuilderGui_FinishcreateDataBlockType[%passedthis,%ctrlIDX]);%i++)
      {
      if (getword($clientcmdObjectBuilderGui_FinishcreateDataBlockType[%passedthis,%ctrlIDX],%i)!$="")
          %passedthis.controls[%ctrlIDX].add(getword($clientcmdObjectBuilderGui_FinishcreateDataBlockType[%passedthis,%ctrlIDX],%i), %i);
      }
   %passedthis.controls[%ctrlIDX].setValue(getWord(%passedthis.field[%passedindex, value], 1));
   %passedthis.controls[%ctrlIDX].setActive(1);
   }

To go from the client to the server I use this function

void NetRemoteRun::RemoteExecute(const char* code)
	{
	bool isfirstsend=true;
	String returnval = String(code);
	int BitSize = 255;
	int bits = mCeil((double)returnval.length()/(double)BitSize);
	for (int i = 0; i < bits; i++)
		{
		int length = BitSize;
		if ((length + (i * BitSize)) > returnval.length())
			length = returnval.length() - (i * BitSize);

		String sbit = returnval.substr( i * BitSize, length);
		if (isfirstsend)
			{
			GameConnection::getConnectionToServer()->postNetEvent(new NetRemoteRun(sbit.c_str(),true,false));
			isfirstsend=false;
			}
		else
			GameConnection::getConnectionToServer()->postNetEvent(new NetRemoteRun(sbit.c_str(),false,false));
		}
	GameConnection::getConnectionToServer()->postNetEvent(new NetRemoteRun("",false,true));
	}

And then as the server recieves the commands, append them back together and then do whatever you want with it.

#2
08/10/2013 (1:35 pm)
Reviving here for needed importance.

I've been trying this out and it seems like every time the client posts the call to the constructor I am met with an immediate access read violation at 0x00000028.

Here's the class code:
class Net_CertificateTransferEvent : public NetEvent {
	public:
		typedef NetEvent Parent;

	private:
		char *mPayload;

	public:
		Net_CertificateTransferEvent(const char * payload = NULL);
		~Net_CertificateTransferEvent() { dFree(mPayload); };

		virtual void pack(NetConnection* conn, BitStream *stream);
		virtual void write(NetConnection* conn, BitStream *stream);
		virtual void unpack(NetConnection* conn, BitStream *stream);
		virtual void process(NetConnection *conn);
};

And the code for the NetEvent:
Net_CertificateTransferEvent::Net_CertificateTransferEvent(const char * payload) {
	if(payload) {
      mPayload = dStrdup(payload);
	}
	else {
	   mPayload = NULL;
	}
}

void Net_CertificateTransferEvent::pack(NetConnection *conn, BitStream *stream) {
	stream->writeString(mPayload);
}

void Net_CertificateTransferEvent::write(NetConnection *conn, BitStream *stream) {
	stream->writeString(mPayload);
}

void Net_CertificateTransferEvent::unpack(NetConnection *conn, BitStream *stream) {
   char buf[256]; 
	stream->readString(buf); 
	mPayload = dStrdup(buf);
}

void Net_CertificateTransferEvent::process(NetConnection *conn) {
   //Code to process data here...
}

Transmit Code:
GameConnection::getConnectionToServer()->postNetEvent(new Net_CertificateTransferEvent(payload));

Where payload contains the string info being sent up.

I've tried putting debug echoes in an that got me nowhere, all I can confirm is that there is data getting to the constructor, and the crash occurs after exiting it, beyond that. No clue.

While we're at it, would someone like to explain how I can go from NetConnection *conn in the ::process command to that connection's GameConnection *con object? That would be very nice, thanks!
#3
08/10/2013 (2:03 pm)
Scrap my last, forgot the two macros in my class def.

I'm wondering however, is there any way to define a NetEvent that is in no way at all exposed to the console (This would be ideal for a EXP system)?

EDIT:

So apparently my data is... much... larger than 256 characters, how do I trim it up and send it to the server in the NetEvent in C++ only, I'm trying to keep out of TS at all costs here.
#4
08/10/2013 (6:04 pm)
Perhaps you can stage the data in the NetEvent object. I would personally store it in a String() object. I think it is better suited to streaming.

Then make sure the NetEvent object only transmits the front 256 bytes of the data and trim that off each time. Of course check for length so it there less than 256 bytes only transmit what is there and pad if necessary. Then write your code this way:
Net_CertificateTransferEvent* event = new Net_CertificateTransferEvent(payload);
while(event->isData())  // you will have to add size method to check how much data is left in the buffer
{
  GameConnection::getConnectionToServer()->postNetEvent(event);
}

Now if this is too laggy maybe you need to find a way to schedule this to only send 256 bytes per frame. I think there is a way to schedule the call in C++ only like there is in script, but I have not personally done this.
#5
08/10/2013 (7:14 pm)
Probably experiencing a dummy moment here, but can you tell me why I'm getting unlimited spam of unknown bytes to my function after all of the correct data sends. Oh, also, the "[END]" isn't added.

Connection established 4264
Mapping string: requestClientCert to index: 0
CertEvent: 10000003Phantom13917872617436349482505654265170894488110909755753431356876722542381577757581273486430119334631238090126750536934
CertEvent: 4868242052096709230158262987276032773928975759:2f4835f1053478d2a8c9381d111a683c660cad2c4e1d62d326e502891ea0d1620feab96a41f0d1ffa
CertEvent: 39d3d7dc0ac432a3063f85dd88978677686fd915b1b569e0576bbfae3c965ec66bb19c857e3230147518235839dc3ecd4f891a33dd46a84e1d276ea414dace15
CertEvent: 8b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855
CertEvent: &Atilde;&deg;&Acirc;&shy;&Acirc;&ordm; <==== Junk like this is spammed up the butt endlessly until a crash after around 30 - 50 seconds

My Code for Break & Transmit:
Net_CertificateTransferEvent *certevent = new Net_CertificateTransferEvent(payload.substr(0, 128).c_str());
	payload = payload.substr(128, payload.size());
	GameConnection::getConnectionToServer()->postNetEvent(certevent); 
	while(payload.size() > 0) {
		if(payload.size() < 128) {
		   //last bit of stuff.
			if(payload.size() > 123) {
            //two transmits needed			
				payload += "[END]";
				//send the first now
				certevent = new Net_CertificateTransferEvent(payload.substr(0, payload.size()).c_str());
				GameConnection::getConnectionToServer()->postNetEvent(certevent); 
				payload = payload.substr(128, payload.size());
				//and hit the next one right away
				certevent = new Net_CertificateTransferEvent(payload.substr(0, payload.size()).c_str());
				GameConnection::getConnectionToServer()->postNetEvent(certevent); 
			}
			else {
				certevent = new Net_CertificateTransferEvent(payload.substr(0, payload.size()).c_str());
				GameConnection::getConnectionToServer()->postNetEvent(certevent); 
			}
			break;
		}
		else {       
		   //post the next event...
		   certevent = new Net_CertificateTransferEvent(payload.substr(0, 128).c_str());
		   payload = payload.substr(128, payload.size());
			GameConnection::getConnectionToServer()->postNetEvent(certevent); 
		}
	}
#6
08/10/2013 (8:45 pm)
1. Why are you creating a new certevent? Why not just resize it in the object each time it calls a method in the postNetEvent? There is no delete in between of certevent, is the certevent a smart pointer? Or add a method to the Net_CertificateTransferEvent to update the data according to the new payload.

2. I think that there are no NULL pointers in a substr. You may need to put one in artificially on the what is extracted from c_str IF you depend on the NULL pointers somewhere.

3. Should both pack and write methods of Net_CertificateTransferEvent be calling stream->writeString? Those are the methods where I would resize the string BTW. Just make sure it is resized on the one that is called 1st.

4. Monitor the size of payload.size() to see if it is shrinking properly.

5. I don't know what would cause that weird crap unless there is something trying to make sense of the data and turning it into unicode.

6. The "else" condition of if(payload.size() > 123) never resizes payload. The code can never get out of the while condition.
#7
08/11/2013 (12:09 pm)
EDIT: Made a quick adjustment, no more junk in my transmit. Now, Access Violations for some reason.

Mapping string: requestClientCert to index: 0
CertEvent: 10000003Phantom13917872617436349482505654265170894488110909755753431356876722542381577757581273486430119334631238090126750536934
Current Payload Length Left: 436
Sending: 4868242052096709230158262987276032773928975759:2f4835f1053478d2a8c9381d111a683c660cad2c4e1d62d326e502891ea0d1620feab96a41f0d1ffa39d3d7dc0ac432a3063f85dd88978677686fd915b1b569e0576bbfae3c965ec66bb19c857e3230147518235839dc3ecd4f891a33dd46a84e1d276ea414dace158b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
setPayload: 4868242052096709230158262987276032773928975759:2f4835f1053478d2a8c9381d111a683c660cad2c4e1d62d326e502891ea0d1620feab96a41f0d1ffa
Current Payload Length Left: 308
Sending: 39d3d7dc0ac432a3063f85dd88978677686fd915b1b569e0576bbfae3c965ec66bb19c857e3230147518235839dc3ecd4f891a33dd46a84e1d276ea414dace158b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
setPayload: 39d3d7dc0ac432a3063f85dd88978677686fd915b1b569e0576bbfae3c965ec66bb19c857e3230147518235839dc3ecd4f891a33dd46a84e1d276ea414dace15
Current Payload Length Left: 180
Sending: 8b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
setPayload: 8b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
CertEvent: (null)
CertEvent: (null)
CertEvent: (null)
CertEvent: (null)
Server got 8b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
First-chance exception at 0x10044660 in Legacies.exe: 0xC0000005: Access violation reading location 0x00000000.
Unhandled exception at 0x77c315de in Legacies.exe: 0xC0000005: Access violation reading location 0x00000000.
The program '[6940] Legacies.exe: Native' has exited with code -1073741819 (0xc0000005).

Note how the server is only getting one transmit for some reason...

S32 trueLength = dStrlen(payload.c_str());
	Net_CertificateTransferEvent *certevent = new Net_CertificateTransferEvent(payload.substr(0, 128).c_str());
	payload = payload.substr(128, trueLength);
	GameConnection::getConnectionToServer()->postNetEvent(certevent); 
	while(dStrlen(payload.c_str()) > 0) {
		Con::printf("Current Payload Length Left: %i\nSending: %s", trueLength, payload.c_str());
      //post the next event...
      trueLength = dStrlen(payload.c_str());
		if(trueLength <= 128) {
			//Last bit of it.
	   	certevent->setPayload(payload.substr(0, trueLength).c_str());
		   payload = "";
		   GameConnection::getConnectionToServer()->postNetEvent(certevent); 
		}
		else {
	   	certevent->setPayload(payload.substr(0, 128).c_str());
		   payload = payload.substr(128, payload.length());
		   GameConnection::getConnectionToServer()->postNetEvent(certevent); 		
		}
	}

#ifndef _NETCERTEVENT
#define _NETCERTEVENT
class Net_CertificateTransferEvent : public NetEvent {
	public:
		typedef NetEvent Parent;

	private:
		char *mPayload;
		String storedData;

	public:
		Net_CertificateTransferEvent(const char * payload = NULL);
		~Net_CertificateTransferEvent() { dFree(mPayload); }

		void setPayload(const char *newPayload);

		virtual void pack(NetConnection* conn, BitStream *stream);
		virtual void write(NetConnection* conn, BitStream *stream);
		virtual void unpack(NetConnection* conn, BitStream *stream);
		virtual void process(NetConnection *conn);

		DECLARE_CONOBJECT(Net_CertificateTransferEvent);
};

IMPLEMENT_CO_NETEVENT_V1(Net_CertificateTransferEvent);
#endif

Net_CertificateTransferEvent::Net_CertificateTransferEvent(const char * payload) {
	Con::printf("CertEvent: %s", payload);
	if(payload) {
      mPayload = dStrdup(payload);
	}
	else {
	   mPayload = NULL;
	}
}

void Net_CertificateTransferEvent::setPayload(const char *newPayload) {
	Con::printf("setPayload: %s", newPayload);
   mPayload = dStrdup(newPayload);
}

void Net_CertificateTransferEvent::pack(NetConnection *conn, BitStream *stream) {
	stream->writeString(mPayload);
}

void Net_CertificateTransferEvent::write(NetConnection *conn, BitStream *stream) {
	stream->writeString(mPayload);
}

void Net_CertificateTransferEvent::unpack(NetConnection *conn, BitStream *stream) {
   char buf[128]; 
	stream->readString(buf); 
	mPayload = dStrdup(buf);
}
 
void Net_CertificateTransferEvent::process(NetConnection *conn) {
	Con::printf("Server got %s", mPayload);

	storedData += mPayload;
	memcpy(mPayload, 0, sizeof(mPayload));
        //process code below, not reached yet...
}
#8
08/11/2013 (1:05 pm)
You might want to look up to see if NetEvent is designed to get the last data sent or if it tries to get everything.
#9
08/11/2013 (1:29 pm)
I did some research and it's not very clear if it is or not, however, I did find something that may help me here. I went through some existing implements of NetEvent that are used y the engine already and there is one that supports String transfers up to 1024 chars, which is way more than enough for my needs. I'll try to duplicate the method provided there and report back with my findings.
#10
08/11/2013 (2:23 pm)
Ok update, this is going to require two posts so please mind the used space. Here's the console log first, clearly diagramming the full transfer process, but crashing when it finishes getting the last of the unpack data.

Mapping string: requestClientCert to index: 0
* Init Cert Transfer
* Done.
setPayload: 10000003Phantom13917872617436349482505654265170894488110909755753431356876722542381577757581273486430119334631238090126750536934
Current Payload Length Left: 436
Sending: 4868242052096709230158262987276032773928975759:2f4835f1053478d2a8c9381d111a683c660cad2c4e1d62d326e502891ea0d1620feab96a41f0d1ffa39d3d7dc0ac432a3063f85dd88978677686fd915b1b569e0576bbfae3c965ec66bb19c857e3230147518235839dc3ecd4f891a33dd46a84e1d276ea414dace158b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
setPayload: 4868242052096709230158262987276032773928975759:2f4835f1053478d2a8c9381d111a683c660cad2c4e1d62d326e502891ea0d1620feab96a41f0d1ffa
Current Payload Length Left: 308
Sending: 39d3d7dc0ac432a3063f85dd88978677686fd915b1b569e0576bbfae3c965ec66bb19c857e3230147518235839dc3ecd4f891a33dd46a84e1d276ea414dace158b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
setPayload: 39d3d7dc0ac432a3063f85dd88978677686fd915b1b569e0576bbfae3c965ec66bb19c857e3230147518235839dc3ecd4f891a33dd46a84e1d276ea414dace15
Current Payload Length Left: 180
Sending: 8b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
setPayload: 8b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
* Pack
* Int packed.
* Packed String 0.
* Packed String 1.
* Packed String 2.
* Packed String 3.
* Init Cert Transfer
* Done.
* Unpack
Need to process 4 payloads
* Got 10000003Phantom13917872617436349482505654265170894488110909755753431356876722542381577757581273486430119334631238090126750536934
* String is now 10000003Phantom13917872617436349482505654265170894488110909755753431356876722542381577757581273486430119334631238090126750536934
* Got 4868242052096709230158262987276032773928975759:2f4835f1053478d2a8c9381d111a683c660cad2c4e1d62d326e502891ea0d1620feab96a41f0d1ffa
* String is now 10000003Phantom139178726174363494825056542651708944881109097557534313568767225423815777575812734864301193346312380901267505369344868242052096709230158262987276032773928975759:2f4835f1053478d2a8c9381d111a683c660cad2c4e1d62d326e502891ea0d1620feab96a41f0d1ffa
* Got 39d3d7dc0ac432a3063f85dd88978677686fd915b1b569e0576bbfae3c965ec66bb19c857e3230147518235839dc3ecd4f891a33dd46a84e1d276ea414dace15
* String is now 10000003Phantom139178726174363494825056542651708944881109097557534313568767225423815777575812734864301193346312380901267505369344868242052096709230158262987276032773928975759:2f4835f1053478d2a8c9381d111a683c660cad2c4e1d62d326e502891ea0d1620feab96a41f0d1ffa39d3d7dc0ac432a3063f85dd88978677686fd915b1b569e0576bbfae3c965ec66bb19c857e3230147518235839dc3ecd4f891a33dd46a84e1d276ea414dace15
* Got 8b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
* String is now 10000003Phantom139178726174363494825056542651708944881109097557534313568767225423815777575812734864301193346312380901267505369344868242052096709230158262987276032773928975759:2f4835f1053478d2a8c9381d111a683c660cad2c4e1d62d326e502891ea0d1620feab96a41f0d1ffa39d3d7dc0ac432a3063f85dd88978677686fd915b1b569e0576bbfae3c965ec66bb19c857e3230147518235839dc3ecd4f891a33dd46a84e1d276ea414dace158b513b426ec0c1ca5ecb1b54634c412ae8c8d1c69dbc855[END]
First-chance exception at 0x101556a8 in Legacies.exe: 0xC0000005: Access violation reading location 0x3242b860.
Unhandled exception at 0x77c315de in Legacies.exe: 0xC0000005: Access violation reading location 0x3242b860.
The program '[6992] Legacies.exe: Native' has exited with code -1073741819 (0xc0000005).
#11
08/11/2013 (2:25 pm)
Any my updated code:
#define MaxBuffers (RSA_KEY_SIZE + 256) / 128
class Net_CertificateTransferEvent : public NetEvent {
	public:
		typedef NetEvent Parent;
	   enum TransferData {
	      MaxIntBits = 4,
	   };

	private:
		int currentPayload;
		char *mPayload[MaxBuffers];
		String storedData;

	public:
		Net_CertificateTransferEvent();
		~Net_CertificateTransferEvent() { for(int i = 0; i < MaxBuffers; i++) dFree(mPayload[i]); }

		void setPayload(const char *newPayload);

		virtual void pack(NetConnection* conn, BitStream *stream);
		virtual void write(NetConnection* conn, BitStream *stream);
		virtual void unpack(NetConnection* conn, BitStream *stream);
		virtual void process(NetConnection *conn);

		DECLARE_CONOBJECT(Net_CertificateTransferEvent);
};

IMPLEMENT_CO_NETEVENT_V1(Net_CertificateTransferEvent);
#endif

Net_CertificateTransferEvent::Net_CertificateTransferEvent() {
	Con::printf("* Init Cert Transfer");
	for(int i = 0; i < MaxBuffers; i++) {
	   mPayload[i] = NULL;
	}
	currentPayload = 0;
	Con::printf("* Done.");
}

void Net_CertificateTransferEvent::setPayload(const char *newPayload) {
	Con::printf("setPayload: %s", newPayload);
   mPayload[currentPayload] = dStrdup(newPayload);
	currentPayload++;
}

void Net_CertificateTransferEvent::pack(NetConnection *conn, BitStream *stream) {
	Con::printf("* Pack");
	stream->writeInt(currentPayload, MaxIntBits);
	Con::printf("* Int packed.");
	for(int i = 0; i < currentPayload; i++) {
	   stream->writeString(mPayload[i]);
      Con::printf("* Packed String %i.", i);
	}
}

void Net_CertificateTransferEvent::write(NetConnection *conn, BitStream *stream) {
	Con::printf("* Write");
	pack(conn, stream);
}

void Net_CertificateTransferEvent::unpack(NetConnection *conn, BitStream *stream) {
	Con::printf("* Unpack");
	S32 payloadCount = stream->readInt(MaxIntBits);
	Con::printf("Need to process %i payloads", payloadCount);
	char buf[128];
	for(int i = 0; i < payloadCount; i++) {
	   stream->readString(buf); 
	   mPayload[i] = dStrdup(buf);	
		Con::printf("* Got %s", mPayload[i]);
		storedData += mPayload[i];
		Con::printf("* String is now %s", storedData.c_str());
	}
}

The process method has been commented out aside from a console print, so that's ruled out. The RSA_KEY_SIZE is 512, so the MaxBuffers field comes to 6. Any ideas why I'm crashing now? (we're down to one single transmit.)
#12
08/11/2013 (2:29 pm)
ALRIGHT.... so my good old friend Con::printf's 1024 limit is plaguing my existence again, my own debug echoes betrayed me (lol).. Ignore my last... Now I have a more "fun" situation...

The event is being looped... Endlessly... And my game doesn't crash anymore. Any idea why? The transmit code has only been slightly adjusted:

S32 trueLength = dStrlen(payload.c_str());
	Net_CertificateTransferEvent *certevent = new Net_CertificateTransferEvent();
	certevent->setPayload(payload.substr(0, 128).c_str());
	payload = payload.substr(128, trueLength);
	while(dStrlen(payload.c_str()) > 0) {
		Con::printf("Current Payload Length Left: %inSending: %s", trueLength, payload.c_str());
      //post the next event...
      trueLength = dStrlen(payload.c_str());
		if(trueLength <= 128) {
			//Last bit of it,and send.
	   	certevent->setPayload(payload.substr(0, trueLength).c_str());
		   payload = "";
		   GameConnection::getConnectionToServer()->postNetEvent(certevent); 
			return;
		}
		else {
	   	certevent->setPayload(payload.substr(0, 128).c_str());
		   payload = payload.substr(128, payload.length());	
		}
	}

EDIT:
This Line:
GameConnection *client = (GameConnection*)conn->getConnectionToServer();

IS causing access violations. Can you tell me how to get the GameConnection object from the NetConnection *conn in ::process?
#13
08/11/2013 (4:31 pm)
Try a dynamic_cast. If that fails you can't get a GameConnection from it.

I can't tell why it would loop. Are you talking about the while loop not exiting.
#14
08/11/2013 (4:56 pm)
This is becoming very confusing.. and concerning as well for engine data transmission.

void Net_CertificateTransferEvent::process(NetConnection *conn) {
	Con::printf("Process!");
	
	String storedData;
	for(S32 i = 0; i < payloadCount; i++) {
	   storedData += mPayload[i];
           Con::printf("%s", mPayload[i]);
	}
	Con::printf("STORED: %s", storedData.c_str());
}

I've stripped my function all the way to this. Even attempting to access "storedData" a variable local to process generates an access violation. I then proceeded to add the printf statement inside the loop, and that too generates an access violation. So for some unknown reason, the character data is being lost in between unpack and process, which should not be happening.

At this point I'm completely lost as to what the problem is, or even how to approach it.

EDIT:

Well, I let my disappointment get the best of me, lol.. It took me one minute to come up with the idea of moving all of my processing code into ::unpack. Doing that, and voila, the code works perfectly. So, I guess the answer for string transmits is to just use ::pack & ::unpack.
#15
08/12/2013 (3:31 am)
Robert,

This is the header file from Oneworld where I transmit the datablock names over the wire from the server to the client.

class NetFetchInspectorDataBlocks_Event: public NetEvent
	{
	public:
		typedef NetEvent Parent;
		friend class NetInspectorEvent_Helper;
		DECLARE_CONOBJECT(NetFetchInspectorDataBlocks_Event);
	private:
		const char* mClassName;
		S32         mMenuID;
		const char* mPayload;
		bool        mFinished;

	public:
		NetFetchInspectorDataBlocks_Event(S32 argc=0, const char **argv=NULL, NetConnection *conn = NULL);
	private:
		NetFetchInspectorDataBlocks_Event(const char* classname,S32 menuid);
		NetFetchInspectorDataBlocks_Event(S32 menuid,const char* payload,bool finished,bool);
	public:
		~NetFetchInspectorDataBlocks_Event();
		virtual void pack(NetConnection* conn, BitStream *stream);
		virtual void write(NetConnection* conn, BitStream *bstream);
		virtual void unpack(NetConnection* conn, BitStream *stream);
		virtual void process(NetConnection *conn);
	};

#16
08/12/2013 (3:33 am)
CPP

IMPLEMENT_CO_NETEVENT_V1(NetFetchInspectorDataBlocks_Event);

NetFetchInspectorDataBlocks_Event::NetFetchInspectorDataBlocks_Event(S32 argc, const char **argv, NetConnection *conn)
	{
	mClassName=StringTable->insert("");
	mMenuID = 0;
	mPayload = StringTable->insert("");
	mFinished=false;
	}

NetFetchInspectorDataBlocks_Event::NetFetchInspectorDataBlocks_Event(const char* classname,S32 menuid)
	{
	mClassName = StringTable->insert(classname);
	mMenuID = menuid;
	mPayload = StringTable->insert("");
	mFinished=false;
	}

NetFetchInspectorDataBlocks_Event::NetFetchInspectorDataBlocks_Event(S32 menuid,const char* payload,bool finished,bool)
	{
	mClassName = StringTable->insert("");
	mPayload = StringTable->insert(payload);
	mMenuID = menuid;
	mFinished=false;
	}


NetFetchInspectorDataBlocks_Event::~NetFetchInspectorDataBlocks_Event(){}
#17
08/12/2013 (3:34 am)
CPP Part 2
void NetFetchInspectorDataBlocks_Event::pack(NetConnection* conn, BitStream *stream)
	{
	char buff[256];
	dStrcpy(buff,mClassName);
	stream->writeString(buff);
	dStrcpy(buff,mPayload);
	stream->writeString(buff);
	stream->write(mMenuID);
	stream->write(mFinished);
	}

void NetFetchInspectorDataBlocks_Event::write(NetConnection* conn, BitStream *bstream)
	{
	pack(conn, bstream);
	}
#18
08/12/2013 (3:36 am)
CPP Part 3
void NetFetchInspectorDataBlocks_Event::unpack(NetConnection* conn, BitStream *stream)
	{
	char buff[256];
	stream->readString(buff);
	mClassName=StringTable->insert(buff);
	stream->readString(buff);
	mPayload=StringTable->insert(buff);
	stream->read(&mMenuID);
	stream->read(&mFinished);
	}
#19
08/12/2013 (3:37 am)
CPP Part 4
void NetFetchInspectorDataBlocks_Event::process(NetConnection *conn)
	{
	if(conn->isConnectionToServer())
		{
		if (mFinished)
			Con::executef("Inspector_FinishcreateDataBlockType",mPayload,Con::getIntArg(mMenuID),"0"); //Con::getIntArg(mMenuID),mPayload,Con::getIntArg(mCtrlIdx),Con::getIntArg(mPassedIndex),"1");
		else
			Con::executef("Inspector_FinishcreateDataBlockType",mPayload,Con::getIntArg(mMenuID),"1");//,Con::getIntArg(mMenuID),mPayload,Con::getIntArg(mCtrlIdx),Con::getIntArg(mPassedIndex),"0");
		}
	else
		{
		//Server recieved command
		String returnval = String("");

		if (dStrcmp(mClassName,"Sim::getSFXParameterGroup")==0)
			{
			SimSet* set = Sim::getSFXParameterGroup();
			for( SimSet::iterator iter = set->begin(); iter != set->end(); ++ iter )
				{
				SFXParameter* parameter = dynamic_cast< SFXParameter* >( *iter );
				if( parameter )
					returnval = returnval + String(parameter->getInternalName()) + String(" ");
				}
			}
		else if (dStrcmp(mClassName,"Sim::getSFXStateSet")==0)
			{
			SimSet* set = Sim::getSFXStateSet();
			for( SimSet::iterator iter = set->begin(); iter != set->end(); ++ iter )
				{
				SFXState* state = dynamic_cast< SFXState* >( *iter );
				if( state )
					returnval = returnval + String(state->getName()) + String(" ");
				}
			}
		else if (dStrcmp(mClassName,"Sim::getSFXSourceSet")==0)
			{
			SimSet* set = Sim::getSFXSourceSet();
			for( SimSet::iterator iter = set->begin(); iter != set->end(); ++ iter )
				{
				SFXSource* source = dynamic_cast< SFXSource* >( *iter );
				if( source && source->getName() )
					returnval = returnval + String(source->getName()) + String(" ");
				}
			}
		else if (dStrcmp(mClassName,"GuiInspectorTypeSFXDescriptionName")==0)
			{
			SimObject* sdbg = Sim::getSFXDescriptionSet();// Sim::findObject("DataBlockGroup");
			if (sdbg)
				{
				SimSet* dbg = dynamic_cast<SimSet*>(sdbg);
				if (dbg)
					{
					for (Vector<SimObject*>::iterator itr = dbg->begin(); itr != dbg->end(); itr++)
						{
						SimObject* obj = *itr;
						returnval = returnval + String(obj->getName()) + String(" ");
						}	
					}	
				}	
			}
		else if (dStrcmp(mClassName,"GuiInspectorTypeSFXTrackName")==0)
			{
			SimObject* sdbg = Sim::getSFXTrackSet();// Sim::findObject("DataBlockGroup");
			if (sdbg)
				{
				SimSet* dbg = dynamic_cast<SimSet*>(sdbg);
				if (dbg)
					{
					for (Vector<SimObject*>::iterator itr = dbg->begin(); itr != dbg->end(); itr++)
						{
						SimObject* obj = *itr;
						returnval = returnval + String(obj->getName()) + String(" ");
						}	
					}	
				}	
			}
#20
08/12/2013 (3:38 am)
cpp Part 5
else if (dStrcmp(mClassName,"GuiInspectorTypeSFXEnvironmentName")==0)
			{
			SimObject* sdbg = Sim::getSFXEnvironmentSet();// Sim::findObject("DataBlockGroup");
			if (sdbg)
				{
				SimSet* dbg = dynamic_cast<SimSet*>(sdbg);
				if (dbg)
					{
					for (Vector<SimObject*>::iterator itr = dbg->begin(); itr != dbg->end(); itr++)
						{
						SimObject* obj = *itr;
						returnval = returnval + String(obj->getName()) + String(" ");
						}	
					}	
				}	

			}
		else if (dStrcmp(mClassName,"GuiInspectorTypeSFXAmbienceName")==0)
			{
			SimObject* sdbg = Sim::getSFXAmbienceSet();// Sim::findObject("DataBlockGroup");
			if (sdbg)
				{
				SimSet* dbg = dynamic_cast<SimSet*>(sdbg);
				if (dbg)
					{
					for (Vector<SimObject*>::iterator itr = dbg->begin(); itr != dbg->end(); itr++)
						{
						SimObject* obj = *itr;
						returnval = returnval + String(obj->getName()) + String(" ");
						}	
					}	
				}	
			}

		else
			{
			SimObject* sdbg = Sim::getDataBlockGroup();// Sim::findObject("DataBlockGroup");
			if (sdbg)
				{
				SimSet* dbg = dynamic_cast<SimSet*>(sdbg);
				if (dbg)
					{
					for (Vector<SimObject*>::iterator itr = dbg->begin(); itr != dbg->end(); itr++)
						{
						SimObject* obj = *itr;
						if(isMemberOfClass(obj->getClassName(),mClassName))
							{
							returnval = returnval + String(obj->getName()) + String(" ");
							}
						}	
					}	
				}	
			}		
		if (returnval.length()>0)
			{
				int BitSize = 128;
				int bits = mCeil((double)returnval.length()/(double)BitSize);
				for (int i = 0; i < bits; i++)
					{
					int length = BitSize;
					if ((length + (i * BitSize)) > returnval.length())
						length = returnval.length() - (i * BitSize);

					String sbit = returnval.substr( i * BitSize, length);
					//Do command back to client here.
					if (returnval.length()==0)
						returnval = String(" ");
					conn->postNetEvent(new NetFetchInspectorDataBlocks_Event(mMenuID,sbit.c_str(),false,false));
					}
				if (returnval.length()==0)
					returnval = String(" ");
				conn->postNetEvent( new NetFetchInspectorDataBlocks_Event(mMenuID,"",true,true));
				}
Page «Previous 1 2