masodikbela

c++ Fixing charselect "update bugs"

10 posts in this topic

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

  • Like 25

Share this post


Link to post
Share on other sites
15 minutes ago, MORTE said:

It works perfectly, but after installing the settings when the character is "naked", without hair / armor, is this normal?

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

  • Like 1

Share this post


Link to post
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.

  • Like 1

Share this post


Link to post
Share on other sites

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 :)

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.