Irrnetlite beta chat client server communication timing

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
chronos1981
Posts: 8
Joined: Wed Mar 19, 2008 12:03 pm

Irrnetlite beta chat client server communication timing

Post by chronos1981 »

I am working on an online game. The game engine will be easy so I'm starting on the network communication side first.

I have the client talking to the server. I can type into the edit box and hit enter, selecting the text from the edit box and sending a packet containing the string to the server. The server displays the string from the client. The problem is, when I try to add this line to the server

"net::SOutPacket outpacket;"

to create the packet to send to the client, the server freezes when I try to send the packet from the client. When I use the SOutPacket command on the client it works fine.

Code: Select all

class ServerNetCallback : public net::INetCallback
{
	// We will store a pointer to the net manager.
	net::INetManager* netManager;
	core::stringc str;

public:
	ServerNetCallback(net::INetManager* netManagerIn) : netManager(netManagerIn) {}
	
	virtual void handlePacket(net::SInPacket& packet)
	{
		packet.deCompressPacket();
		packet >> str;
		stringw mess = str.c_str();
		root->getElementFromId(EDIT_ID, true)->setText(mess.c_str()); 
		if(netManager->getConnectionStatus() != net::EICS_FAILED)
		{
			net::SOutPacket outpacket;  //program crashes on this line
			outpacket << str.c_str();
			outpacket.compressPacket();
			netManager->sendOutPacket(outpacket);
		}
		
			
	}
};
obviously I'm doing something wrong. I went by example1.cpp that came with irrnetlite beta. I have compiled it and it works.


Code: Select all

class ServerNetCallback : public net::INetCallback
{
	// We will store a pointer to the net manager.
	net::INetManager* netManager;

	// Here we will store the cannon's power and angle.
	// Remember that f32 is just a typedef for float.
	f32 cannonPower;
	f32 cannonAngle;
public:
	ServerNetCallback(net::INetManager* netManagerIn) : netManager(netManagerIn) {}
	
	
	// Our handlePacket function.
	virtual void handlePacket(net::SInPacket& packet)
	{
		// The packets will use a single char to store
		// the packet identifier, remember to use the
		// smallest possible datatype for storing your
		// packet identifiers. c8 is a typedef for char.
		c8 packetid;
		packet >> packetid;
		
		// Here we will switch based on the packet id.
		switch((E_PACKET_TYPE)packetid)
		{
		case EPT_ROTATION:
			// We obtain the cannon angle from the packet.
			packet >> cannonAngle;
			std::cout << "The cannon angle is now " << cannonAngle << std::endl;
			break;
		case EPT_POWER:
			// Same here.
			packet >> cannonPower;
			std::cout << "The cannon power is now " << cannonPower << std::endl;
			break;
		case EPT_MESSAGE:
			// Now this is a special case (Pun intended, or is it even a pun?... nevermind),
			// The client has sent us a message as a string, so we will just print that
			// to the console.
			core::stringc message;
			packet >> message;
			
			// We can obtain a unique "player id" from a packet identifying the client that
			// sent it. More details about the player id in a later example, for now we will
			// just print it out with the message so we know whos saying what.
			std::cout << "Client " << packet.getPlayerId() << " says: " << message.c_str();
			std::cout << std::endl;
			break;
		}
		
		// After handling a packet, we will send an updated status of the cannon to all clients.
		net::SOutPacket rotationPacket;
		
		// The packet id is the first thing that goes in a packet. Note that I am casting it to a char,
		// because that is what we want to store it as, to save space. Be careful to use the same types
		// when sending and receiving, don't send as a char and receive as an int, it will cause trouble.
		rotationPacket << (c8)EPT_ROTATION;
		rotationPacket << cannonAngle;
		
		// Send the packet to all connected clients.
		netManager->sendOutPacket(rotationPacket);
		
		// Send a power update too.
		net::SOutPacket powerPacket;
		powerPacket << (c8)EPT_POWER;
		powerPacket << cannonPower;
		netManager->sendOutPacket(powerPacket);
	}
};
Granted the example1.cpp is also getting packet id.

does it have something to do with "netManager->update(1000);"

Sorry in advance for the fragmented text, I'm just trying to get as much info as possible, and before anyone says it I did use the Search feature and I'm still a little confused. Any help, would be welcome. Just point me in the right direction to the answers.
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Hi there chronos (hon?),

I can't do much unless you provide a simple test case that demonstrates this issue. Since your game engine is still in early stages it shouldn't be very hard to strip everything but the offending parts and isolate the problem. I would be glad to have a look over it once you have done this.

If you could modify the examples to behave the same that would also work.

Cheers
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
chronos1981
Posts: 8
Joined: Wed Mar 19, 2008 12:03 pm

Post by chronos1981 »

ok I have stripped the server code down to the bare bones just console.

Code: Select all

#include <irrlicht.h>
#include <irrNet.h>
#include <iostream>

using namespace irr;
using namespace core;

#pragma comment(lib, "irrNetLite.lib")
#pragma comment(lib, "ws2_32.lib")

net::INetManager* netManager;
class MyNetCallback : public net::INetCallback
{
	
public:
	
	virtual void handlePacket(net::SInPacket& packet)
	{

		packet.deCompressPacket();
		core::stringc str;
		packet >> str;
		// Print the values to the console.
		std::cout << "Message: " << str.c_str();
		std::cout << std::endl;
		
		if(netManager->getConnectionStatus() != net::EICS_FAILED)
		{
			net::SOutPacket outpacket;
			outpacket << str.c_str();
			outpacket.compressPacket();
			netManager->sendOutPacket(outpacket);
			netManager->update(100);
		}

	}
};

int main()
{	
	// Create a server and pass in a new instance of our callback class. The default
	// port that clients can connect to is set to 45000.
	MyNetCallback* netCallback = new MyNetCallback();
	netManager = net::createIrrNetServer(netCallback);netManager->setVerbose(true);
	while(netManager->getConnectionStatus() != net::EICS_FAILED)
	{
		std::cout << "im still here";  //debugging
		std::cout << std::endl;
		netManager->update(1000);
	}
	// Don't forget to clean up!
	delete netManager;
	delete netCallback;
	return 0;
}
I noticed when player 2 (actually it only works with even players, odd players freeze the server) chats it works fine now, but the problem seems to be coming from player 1 (odd player) when it chats the message goes to the server, then the server freezes, while writing this reply, I added some debuging to see if it was freezing or if

if (netManager->getConnectionStatus() == net::EICS_FAILED)
{
std::cout << "Connection lost!!";
std::cout << std::endl;
}

the if statement never passed.

As long as I use the even numbered instances of the client it works fine.

here is the code for the client

Code: Select all

//character allignment neutral at begining actions decide good or bad.
//some races more powerful evil and some more powerful at good
//Galie resurection


#include <stdio.h>
#include <winsock2.h>
#include <irrlicht.h>
#include <irrNet.h>
#include <wchar.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <enet/enet.h>

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#pragma comment(lib, "irrNetLite.lib")
#pragma comment(lib, "ws2_32.lib")
#endif


enum
{
	EDIT_ID,
	CHAT_ID
};

gui::IGUIElement* root;
wchar_t * buff;
wchar_t * buffB;
stringc test1 ;
stringw test2 ;
int keyInput;
bool chat;


IrrlichtDevice *device ;
IVideoDriver* driver ;
ISceneManager* smgr ;
IGUIEnvironment* guienv ;
IGUIEditBox* editbox;
IGUIListBox* chatbox;
net::INetManager* netManager;

// The client callback.
class MyNetCallback : public net::INetCallback
{
	stringc str;
public:
	// Our handlePacket function.
	virtual void handlePacket(net::SInPacket& packet)
	{
		packet.deCompressPacket();
		packet >> str;
		stringw mess = str.c_str();
		chatbox->addItem(mess.c_str());
	}
};

class MyEventReceiver : public IEventReceiver
{
public:
	virtual bool OnEvent(const SEvent& event)
	{
		if (event.KeyInput.PressedDown == true && event.KeyInput.Key == KEY_RETURN)
		{
			if(guienv->hasFocus(editbox) == true)
			{
				chat = false;
			}
			else if(guienv->hasFocus(editbox) == false)
			{
				chat = true;
			}

			if (chat == true) guienv->setFocus(editbox);

			if (chat == false) 
			{
				if(netManager->getConnectionStatus() != net::EICS_FAILED)
				{

					net::SOutPacket packet;
					test1 = editbox->getText();
					packet << test1.c_str();
					packet.compressPacket();
					netManager->sendOutPacket(packet);
					editbox->setText(L"");
					guienv->removeFocus(editbox);
					netManager->update(10);
				}
			}
		}
		return false;
	}

};

int main(int argc, char **argv)
{
	MyEventReceiver receiver;

	device = createDevice( video::EDT_SOFTWARE, dimension2d<u32>(800, 600), 16,false, false, false, &receiver);
	device->setWindowCaption(L"Irrlicht MMORPG");
	driver = device->getVideoDriver();
	smgr = device->getSceneManager();
	guienv = device->getGUIEnvironment();
	//guienv->addStaticText(L"Irrlicht MMORPG",rect<s32>(10,10,260,22), true);
	smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
	chatbox = guienv->addListBox(rect<s32>(0,500,400,580),0,CHAT_ID,false);
	editbox = guienv->addEditBox(L"", rect<s32>(0, 580, 400, 600), true, 0, EDIT_ID);
	editbox->setMultiLine(false);
	root = guienv->getRootGUIElement();

	MyNetCallback* netCallback = new MyNetCallback();
	netManager = net::createIrrNetClient(netCallback, "127.0.0.1");
	netManager->setVerbose(true);	

	if (!device)
		return 1;

	while(device->run())
	{
		driver->beginScene(true, true, SColor(255,100,101,140));
		smgr->drawAll();
		guienv->drawAll();

		if(netManager->getConnectionStatus() != net::EICS_FAILED)
			netManager->update(10);

		driver->endScene();

	}
	device->drop();
	delete netManager;
	delete netCallback;
	return 0;
I know I am probably doing something dumb.
JeroenP
Posts: 11
Joined: Sat Jun 20, 2009 7:05 pm
Location: Belgium
Contact:

Post by JeroenP »

Hello,

I did never worked with irrNet (first time I heard from it), so I can be wrong.

But maybe you could try to remove the netManager->update(100) in this code.

Code: Select all

      if(netManager->getConnectionStatus() != net::EICS_FAILED)
      {
         net::SOutPacket outpacket;
         outpacket << str.c_str();
         outpacket.compressPacket();
         netManager->sendOutPacket(outpacket);
         netManager->update(100);
      } 
In the main-loop, it's already updating, so why should you call it another time in this code?

If I'm right, the update-method calls methods like handlePacket. So if you call update from in handlePacket, update can call handlePacket and handlePacket calls update and update calls handlePacket and ...

Well I could be wrong...

Jeroen
chronos1981
Posts: 8
Joined: Wed Mar 19, 2008 12:03 pm

Post by chronos1981 »

I removed #include <irrlicht.h> from the server code and now it works.
Post Reply