Premium masodikbela 1359 Posted May 14, 2016 Premium Share Posted May 14, 2016 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 1 1 2 17 The one and only UI programming guideline Link to comment Share on other sites More sharing options...
BackPlayer 55 Posted May 14, 2016 Share Posted May 14, 2016 i will test it looks great! Link to comment Share on other sites More sharing options...
TheMt2 11 Posted May 14, 2016 Share Posted May 14, 2016 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.. Link to comment Share on other sites More sharing options...
Premium masodikbela 1359 Posted May 14, 2016 Author Premium Share Posted May 14, 2016 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 More sharing options...
Bot Metin2 Dev 4879 Posted May 14, 2016 Bot Share Posted May 14, 2016 Is it unnessecary where i add that function in interfacemodule.py? Cause i don't have that function: def RemoveQuestDialog(self, key): Link to comment Share on other sites More sharing options...
Premium masodikbela 1359 Posted May 14, 2016 Author Premium Share Posted May 14, 2016 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 More sharing options...
Bot Metin2 Dev 4879 Posted May 14, 2016 Bot Share Posted May 14, 2016 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? Link to comment Share on other sites More sharing options...
Premium masodikbela 1359 Posted May 14, 2016 Author Premium Share Posted May 14, 2016 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 More sharing options...
ZenkoKXO. 29 Posted May 14, 2016 Share Posted May 14, 2016 I tried all possibilities that would lead to a problem; there's no syserr and no problem, quests are correctly closed for the players during the reload so nobody should have a problem with it. Thank you Link to comment Share on other sites More sharing options...
scrabbyyy 20 Posted May 14, 2016 Share Posted May 14, 2016 1 hour ago, masodikbela said: 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). can u share your windows server files with us pleasee Link to comment Share on other sites More sharing options...
ds_aim 241 Posted May 14, 2016 Share Posted May 14, 2016 Just now, scrabbyyy said: can u share your windows server files with us pleasee Dude you are really crazy ? In 6-7 months you don't found a windows serverfiles? Really ? Link to comment Share on other sites More sharing options...
scrabbyyy 20 Posted May 14, 2016 Share Posted May 14, 2016 4 minutes ago, ds_aim said: Dude you are really crazy ? In 6-7 months you don't found a windows serverfiles? Really ? yes didnt find still Link to comment Share on other sites More sharing options...
Active Member Mind Rapist 188 Posted May 19, 2016 Active Member Share Posted May 19, 2016 @masodikbela saves the day again thanks buddy you are top 1 Link to comment Share on other sites More sharing options...
terrorr 15 Posted May 23, 2016 Share Posted May 23, 2016 iteritems() LoL 1 Link to comment Share on other sites More sharing options...
Bot Metin2 Dev 4879 Posted August 20, 2016 Bot Share Posted August 20, 2016 Hey guys, I've spotted one problem with this. I can't click to anything after questboard hide. This problem disappear when I press Esc key. Something is not hidden, did anobyody had this problem too? Link to comment Share on other sites More sharing options...
silvermen 1 Posted October 23, 2016 Share Posted October 23, 2016 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 More sharing options...
Honorable Member xP3NG3Rx 19677 Posted October 24, 2016 Honorable Member Share Posted October 24, 2016 (edited) 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 October 24, 2016 by xP3NG3Rx Explain 5 Link to comment Share on other sites More sharing options...
Recommended Posts