Jump to content

Command - /reload q - Crash Fix


Recommended Posts

  • Premium

Hi there devs,

About a few days ago one of my friends asked me if I could make a fix for the reload q problem. Maybe now some of you are saying "lol what the hell is he talking about, my reload q works perfectly..." and rightfully, because basically it works, it does its job on a test server with no players. But if you try to do a 'reload q' on a real server with players it has a high chance that it will crash the core. You can ask me again "why the hell do you want to reload the quest on a real server instead of fully rebooting the server?" and my answer is a question too: "why not?" Its more faster to add new quests and repair already installed ones, IF this function works well.

Explanation of the crash

Spoiler

As usually I captured the "method of the problem solving". Also at the beginning of the video you can see the crash, and at the end how it will looks like when you set-up the fix.

Okay, but why does it crash???

As you can see in the video, the crash appears when a player open a quest that has a button, and if you do a reload q while its player didn't close that quest window, and after the reload finished he clicks on that button.
The game's "quest system" uses a "suspend and resume" method. What do I mean by this? Once the processing of a quest reaches a line that contains a function that wants something from the player, (wait(), input(), select(), etc) it suspends the quest, then saves its state to a variable. After the player "answered", it will resume the quest, so it will continue from that line it stopped.

And here comes the problem. What does a reload q exactly do? It removes all the quests from the memory and then reload them. So if a player click on a quest button after the reload, the server will try to load the suspended quest's state from the mentioned variable, but its a pointer, so it only contains a memory position where the real data is, and because we did a reload, this position no loner exists, but the game don't know it because it only sees that the variable has a value so it will just do its job. Once the processing reaches a point where it really wants to use that "quest state" data it will crash.

So the solution is: clear all this variables for all the players.

The fix of the crash

Spoiler

src/game

questmanager.h:
Under this:


PC * GetPCForce(unsigned int pc);

Insert this: 

void		StopAllRunningQuests();

questmanager.cpp:

Under this:


	void CQuestManager::DisconnectPC(LPCHARACTER ch)
	{
		m_mapPC.erase(ch->GetPlayerID());
	}

Insert this:


	void CQuestManager::StopAllRunningQuests()
	{
		for (PCMap::iterator it = m_mapPC.begin(); it != m_mapPC.end(); it++)
		{
			it->second.CancelRunning();
			LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindByPID(it->first);
			if (!pkChr || !(pkChr->GetDesc()))
				continue;
			struct ::packet_script packet_script;

			packet_script.header = HEADER_GC_SCRIPT;
			packet_script.skin = QUEST_SKIN_NOWINDOW;
			string data = "[DESTROY_ALL]";
			packet_script.src_size = data.size();
			packet_script.size = packet_script.src_size + sizeof(struct packet_script);

			TEMP_BUFFER buf;
			buf.write(&packet_script, sizeof(struct packet_script));
			buf.write(&data[0], data.size());

			pkChr->GetDesc()->Packet(buf.read_peek(), buf.size());
		}
	}

Still in this file under this:


	void CQuestManager::Reload()
	{

Insert this:


StopAllRunningQuests();

binary

PythonNetworkStream.h:

Under this:


void OnScriptEventStart(int iSkin, int iIndex);

Insert this:


void HideQuestWindows();

PythonNetworkStream.cpp:

Insert this to the end of the file:


void CPythonNetworkStream::HideQuestWindows()
{
	PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "HideAllQuestWindow", Py_BuildValue("()"));
}

PythonNetworkStreamPhaseGame.cpp:

In the bool CPythonNetworkStream::RecvScriptPacket() function after this:


str[str.size()-1] = '\0';

Insert this:


	if (str.compare(0, 13, "[DESTROY_ALL]") == 0)
	{
		CPythonNetworkStream::Instance().HideQuestWindows();
		return true;
	}

root files(client)

interfacemodule.py:

Before this function:


def RemoveQuestDialog(self, key):

Insert this:


	def HideAllQuestWindow(self):
		tempList = []
		for i,v in self.wndQuestWindow.iteritems():
			tempList.append(v)

		for i in tempList:
			i.OnCancel()

game.py:

Under this:


def OpenQuestWindow(self, skin, idx):
		self.interface.OpenQuestWindow(skin, idx)

Insert this:


	def HideAllQuestWindow(self):
		self.interface.HideAllQuestWindow()

And we are done :)

And finally let me wish you all good luck for the setup ;) If you have further question(s), remark(s), or anything that you want to ask or suggest, feel free to post it here, or send it in PM.

If you get error(s) please upload the affected (and edited) file to http://pastebin.com/ and link it in your post, to make my work easier and probably I will be able to help you only in one post, so please spare me from asking basic requests like "Could you upload...". Thank you ;)

Have a nice day,
~masodikbela

 

  • Metin2 Dev 1
  • Confused 1
  • Good 2
  • Love 17

The one and only UI programming guideline

Link to comment
Share on other sites

  • Premium
39 minutes ago, TheMt2 said:

Hey

Thx for share.

I have other problem, when /reload q, quest crash...

Exemple: If player lvl 250 login, item of creat character is gived..

I don't really understand, could you make a video or something about the crash?

The one and only UI programming guideline

Link to comment
Share on other sites

  • Premium
2 minutes ago, Cyber36 said:

Is it unnessecary where i add that function in interfacemodule.py?

Cause i don't have that function: 


def RemoveQuestDialog(self, key):

You can add that thing anywhere in the file, the important thing is to stay in the current class (class Interface(object):).

The one and only UI programming guideline

Link to comment
Share on other sites

  • Bot
58 minutes ago, masodikbela said:

You can add that thing anywhere in the file, the important thing is to stay in the current class (class Interface(object):).

Okay thank you very much :)

Good explanation and tutorial! Only one question more: The operation system you use wasn't freebsd and the compiler not gcc or?

How did you copied the .exe to a path and the server started with that, don't you need an ftp for a server?

english_banner.gif

Link to comment
Share on other sites

  • Premium
Just now, Cyber36 said:

Okay thank you very much :)

Good explanation and tutorial! Only one question more: The operation system you use wasn't freebsd and the compiler not gcc or?

How did you copied the .exe to a path and the server started with that, don't you need an ftp for a server?

I'm using vc120 (visual studio 2013) on my windows 10 operation system. I compiled the server on windows so I can use it as an application (.exe).

The one and only UI programming guideline

Link to comment
Share on other sites

  • 2 months later...
  • 2 months later...

	1024 00:28:01058 :: Traceback (most recent call last):
	1024 00:28:01058 ::   File "game.py", line 709, in HideAllQuestWindow
	1024 00:28:01058 ::   File "interfaceModule.py", line 711, in HideAllQuestWindow
	1024 00:28:01058 :: AttributeError
1024 00:28:01058 :: : 
1024 00:28:01058 :: 'list' object has no attribute 'iteritems'
1024 00:28:01058 :: 
	

Link to comment
Share on other sites

  • Honorable Member

Change your HideAllQuestWindow function to this:

	def HideAllQuestWindow(self):
		[obj.OnCancel() for obj in self.wndQuestWindow]

 

This is need in that case if your self.wndQuestWindow variable is a list( [] ) what hasn't attribute "iteritems" as the errorlog said also.
That one-line command will iterate each items in the list, and that will call the "OnClose" method on every object in the list.
Same as this:

	def HideAllQuestWindow(self):
		for obj in self.wndQuestWindow:
			obj.OnClose()

or this:

	def HideAllQuestWindow(self):
		for i in xrange(len(self.wndQuestWindow)):
			self.wndQuestWindow[i].OnClose()

or...

	def HideAllQuestWindow(self):
		map(lambda x:x.OnClose(), self.wndQuestWindow)

and many more opportunities...

Edited by xP3NG3Rx
Explain
  • Love 5
Link to comment
Share on other sites

Announcements



×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.