Jump to content

Fixing Charselect - Update Bugs


Recommended Posts

  • Premium

Hi there devs,

A few months ago I've made a solution for the well-known problems with the character select/logging out which is:

  • once you are about to change character, the stats (ht, st, playtime, etc...) and parts (armor/head) don't update properly: you have to do it twice to see the correct values/items
  • when a character is logging out from the game near to your character you can see a fast equipment change (the character is unequipping everything from him/herself)

Explanation for the problems

Spoiler

 

When you perform a login or enter the game the client receives the necessary information for the charselect about your characters. The server sends this packet twice: once you log in into your account and when you select your character. After this the client will use this information in the future. So when you go back to the character select, you will see the old stats and parts. After that when you select your character again, the server sends the mentioned packet again, so when you do a second character change you will see the "updated" things.

The reason for the second problem a little different. When a CHARACTER class is being deleted it also deletes the items from the character via the function RemoveFromCharacter. Here after the if (m_bEquipped) part you can see it calls the Unequip() function which will call SendUpdatePacket. Solving this problem possibly could give a little performance too in some cases since when lots of characters standing near to each other (for example in map1s) when someone do a logout the server have to "broadcast" lots of update packets to the characters, and their clients have to remove the parts from the affected character.

 

 

The usual coding video

The fix

Spoiler

server/char.cpp

Spoiler

Add this to the void CHARACTER:: Disconnect(const char * c_pszReason) function: //this is for the playtime update





		packet_point_change pack;
		pack.header = HEADER_GC_CHARACTER_POINT_CHANGE;
		pack.dwVID = m_vid;
		pack.type = POINT_PLAYTIME;
		pack.value = GetRealPoint(POINT_PLAYTIME) + (get_dword_time() - m_dwPlayStartTime) / 60000;
		pack.amount = 0;
		GetDesc()->Packet(&pack, sizeof(struct packet_point_change));

Above this:





GetDesc()->BindCharacter(NULL);

In the function void CHARACTER::UpdatePacket() add this: //this will prevent the server to send update packets about a currently logging out character





	if (IsPC() && (!GetDesc() || !GetDesc()->GetCharacter()))
		return;

After this:





	if (GetSectree() == NULL) return;

 

client/PythonNetworkStreamPhaseGameActor.cpp

Spoiler

Add this to the function CPythonNetworkStream::__RecvCharacterUpdatePacket(SNetworkUpdateActorData * pkNetUpdateActorData) //this will update the saved parts about your character when you change armor/hair





		m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].wHairPart = pkNetUpdateActorData->m_dwHair;
		m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].wMainPart = pkNetUpdateActorData->m_dwArmor;

After this:





		__RefreshInventoryWindow();

 

client/PythonNetworkStreamPhaseLoading.cpp

Spoiler

In the function bool CPythonNetworkStream::__RecvPlayerPoints() replace this //this will update the saved stats of your character when the server sends them during the loading phase





	for (DWORD i = 0; i < POINT_MAX_NUM; ++i)
		CPythonPlayer::Instance().SetStatus(i, PointsPacket.points[i]);

with this:





	for (DWORD i = 0; i < POINT_MAX_NUM; ++i)
	{
		CPythonPlayer::Instance().SetStatus(i, PointsPacket.points[i]);
		if (i == POINT_LEVEL)
			m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byLevel = PointsPacket.points[i];
		else if (i == POINT_ST)
			m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byST = PointsPacket.points[i];
		else if (i == POINT_HT)
			m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byHT = PointsPacket.points[i];
		else if (i == POINT_DX)
			m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byDX = PointsPacket.points[i];
		else if (i == POINT_IQ)
			m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byIQ = PointsPacket.points[i];

	}

 

client/PythonNetworkStreamPhaseGame.cpp

Spoiler

In the function bool CPythonNetworkStream::RecvPointChange() replace this //this will update the saved stats of your character when they are about to change during game phase





			case POINT_LEVEL:
			case POINT_ST:
			case POINT_DX:
			case POINT_HT:
			case POINT_IQ:
				__RefreshStatus();
				__RefreshSkillWindow();
				break;

With this:





			case POINT_PLAYTIME:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].dwPlayMinutes = PointChange.value;
				break;
			case POINT_LEVEL:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byLevel = PointChange.value;
				__RefreshStatus();
				__RefreshSkillWindow();
				break;
			case POINT_ST:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byST = PointChange.value;
				__RefreshStatus();
				__RefreshSkillWindow();
				break;
			case POINT_DX:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byDX = PointChange.value;
				__RefreshStatus();
				__RefreshSkillWindow();
				break;
			case POINT_HT:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byHT = PointChange.value;
				__RefreshStatus();
				__RefreshSkillWindow();
				break;
			case POINT_IQ:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byIQ = PointChange.value;
				__RefreshStatus();
				__RefreshSkillWindow();
				break;

 

 

GL for the setup and 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(s) 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 7
  • Love 33

The one and only UI programming guideline

Link to comment
Share on other sites

  • 4 months later...
On 13/11/2017 at 6:24 PM, Matuszka said:

You made something wrong then. I've got this from a long time ago and works well, without problems.

I checked everything, in the part of "char.cpp / game" is it anyway?

 

https://metin2.download/picture/r3F9504x09DVmF8K988YXgTtGTP6KMUj/.gif

Edited by Metin2 Dev
Core X - External 2 Internal
Link to comment
Share on other sites

Probably you have sash/acce and that's the problem.

In client/PythonNetworkStreamPhaseGameActor.cpp

Search for:

void CPythonNetworkStream::__RecvCharacterUpdatePacket(SNetworkUpdateActorData * pkNetUpdateActorData)

Paste this:

m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].wSashPart = pkNetUpdateActorData->m_dwSash;

Below this:

m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].wMainPart = pkNetUpdateActorData->m_dwArmor;

Maybe you have dwAcce instead of sash.

  • Love 2
Link to comment
Share on other sites

  • 1 year later...

Ok this is something awesome I've never thought before... Tried it but noticed that when I logout while I'm mounting a horse or something and my stats are not raised up they get stored as they show on the horse. For example I'm Level 1 and while riding my VIT is 36, I logout, VIT in character select shows 36.

Great tut and great video :)

Link to comment
Share on other sites

  • 2 weeks later...
  • 1 year later...
On 7/9/2017 at 11:53 AM, masodikbela said:

Hi there devs,

A few months ago I've made a solution for the well-known problems with the character select/logging out which is:

  • once you are about to change character, the stats (ht, st, playtime, etc...) and parts (armor/head) don't update properly: you have to do it twice to see the correct values/items
  • when a character is logging out from the game near to your character you can see a fast equipment change (the character is unequipping everything from him/herself)

Explanation for the problems

  Hide contents

 

When you perform a login or enter the game the client receives the necessary information for the charselect about your characters. The server sends this packet twice: once you log in into your account and when you select your character. After this the client will use this information in the future. So when you go back to the character select, you will see the old stats and parts. After that when you select your character again, the server sends the mentioned packet again, so when you do a second character change you will see the "updated" things.

The reason for the second problem a little different. When a CHARACTER class is being deleted it also deletes the items from the character via the function RemoveFromCharacter. Here after the if (m_bEquipped) part you can see it calls the Unequip() function which will call SendUpdatePacket. Solving this problem possibly could give a little performance too in some cases since when lots of characters standing near to each other (for example in map1s) when someone do a logout the server have to "broadcast" lots of update packets to the characters, and their clients have to remove the parts from the affected character.

 

 

The usual coding video

The fix

  Reveal hidden contents

server/char.cpp

  Reveal hidden contents

Add this to the void CHARACTER:: Disconnect(const char * c_pszReason) function: //this is for the playtime update




		packet_point_change pack;
		pack.header = HEADER_GC_CHARACTER_POINT_CHANGE;
		pack.dwVID = m_vid;
		pack.type = POINT_PLAYTIME;
		pack.value = GetRealPoint(POINT_PLAYTIME) + (get_dword_time() - m_dwPlayStartTime) / 60000;
		pack.amount = 0;
		GetDesc()->Packet(&pack, sizeof(struct packet_point_change));

Above this:




GetDesc()->BindCharacter(NULL);

In the function void CHARACTER::UpdatePacket() add this: //this will prevent the server to send update packets about a currently logging out character




	if (IsPC() && (!GetDesc() || !GetDesc()->GetCharacter()))
		return;

After this:




	if (GetSectree() == NULL) return;

 

client/PythonNetworkStreamPhaseGameActor.cpp

  Reveal hidden contents

Add this to the function CPythonNetworkStream::__RecvCharacterUpdatePacket(SNetworkUpdateActorData * pkNetUpdateActorData) //this will update the saved parts about your character when you change armor/hair




		m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].wHairPart = pkNetUpdateActorData->m_dwHair;
		m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].wMainPart = pkNetUpdateActorData->m_dwArmor;

After this:




		__RefreshInventoryWindow();

 

client/PythonNetworkStreamPhaseLoading.cpp

  Reveal hidden contents

In the function bool CPythonNetworkStream::__RecvPlayerPoints() replace this //this will update the saved stats of your character when the server sends them during the loading phase




	for (DWORD i = 0; i < POINT_MAX_NUM; ++i)
		CPythonPlayer::Instance().SetStatus(i, PointsPacket.points[i]);

with this:




	for (DWORD i = 0; i < POINT_MAX_NUM; ++i)
	{
		CPythonPlayer::Instance().SetStatus(i, PointsPacket.points[i]);
		if (i == POINT_LEVEL)
			m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byLevel = PointsPacket.points[i];
		else if (i == POINT_ST)
			m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byST = PointsPacket.points[i];
		else if (i == POINT_HT)
			m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byHT = PointsPacket.points[i];
		else if (i == POINT_DX)
			m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byDX = PointsPacket.points[i];
		else if (i == POINT_IQ)
			m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byIQ = PointsPacket.points[i];

	}

 

client/PythonNetworkStreamPhaseGame.cpp

  Reveal hidden contents

In the function bool CPythonNetworkStream::RecvPointChange() replace this //this will update the saved stats of your character when they are about to change during game phase




			case POINT_LEVEL:
			case POINT_ST:
			case POINT_DX:
			case POINT_HT:
			case POINT_IQ:
				__RefreshStatus();
				__RefreshSkillWindow();
				break;

With this:




			case POINT_PLAYTIME:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].dwPlayMinutes = PointChange.value;
				break;
			case POINT_LEVEL:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byLevel = PointChange.value;
				__RefreshStatus();
				__RefreshSkillWindow();
				break;
			case POINT_ST:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byST = PointChange.value;
				__RefreshStatus();
				__RefreshSkillWindow();
				break;
			case POINT_DX:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byDX = PointChange.value;
				__RefreshStatus();
				__RefreshSkillWindow();
				break;
			case POINT_HT:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byHT = PointChange.value;
				__RefreshStatus();
				__RefreshSkillWindow();
				break;
			case POINT_IQ:
				m_akSimplePlayerInfo[m_dwSelectedCharacterIndex].byIQ = PointChange.value;
				__RefreshStatus();
				__RefreshSkillWindow();
				break;

 

 

GL for the setup and 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(s) 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

Hy , all armours works well but what about costumes and costumes hair?

Link to comment
Share on other sites

  • 4 years later...

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.