Jump to content
metin2dev
Metin2International
Sign in to follow this  
Syreldar

[Affect Fix] Weaponry Sura's Dispel and Healing Power Shaman's Heal Lag Bug

Recommended Posts

Hello, pretty sure anyone of you knows about the Dispel and Heal Lag problem that has been around since always.

This little modification will fix both these problems completely. (Thanks @Horinna for helping with the in-game tests)

 

Problem:

The RemoveAffect function calls ComputePoints() (Complete rearrange of all the player stats and equip parts, one of the heaviest checks). The correct function to use is RefreshAffect() which does its job pretty fine!

But that's not the only problem: Based on the current code, that function would get called every single time an affect gets removed or added, while it should only get called once, at the end of the process.

Solution: We could make new functions for those 2 special flags (REMOVE_BAD_AFFECT and REMOVE_GOOD_AFFECT), but in order to keep things simple for you guys, i'll simply "dynamicize" the RemoveAffect function.

 

1. go to char_affect.cpp:

Spoiler

 

find:


bool CHARACTER::RemoveAffect(CAffect * pkAff)

substitute with:


bool CHARACTER::RemoveAffect(CAffect * pkAff, bool single)

inside it find:


	if (AFFECT_REVIVE_INVISIBLE != pkAff->dwType)
		ComputePoints();
	else
		UpdatePacket();

substitute it with:


	if (single)
		if (AFFECT_REVIVE_INVISIBLE != pkAff->dwType)
			ComputePoints();
		else
			UpdatePacket();
1
1
2
2
2

2: go to char.h:

Spoiler

find:


		bool			RemoveAffect(CAffect * pkAff);

substitute:


		bool			RemoveAffect(CAffect * pkAff, bool single = true);
 
 
 

 

This way, we applied a simple boolean value arg to the RemoveAffect function, which will get set to true by default.

By setting it to false like this

RemoveAffect(affectLUL, false);

we are basically saying the game to not Rearrange the points when affectLUL gets removed.

now we will use a cycle to do that for every affect like usual, and we will rearrange of the points just once, at the end of the process, like it should be.

 

3. In char_affect.cpp:

Spoiler

find:


void CHARACTER::RemoveGoodAffect()
{
	RemoveAffect(AFFECT_MOV_SPEED);
	RemoveAffect(AFFECT_ATT_SPEED);
	RemoveAffect(AFFECT_STR);
	RemoveAffect(AFFECT_DEX);
	RemoveAffect(AFFECT_INT);
	RemoveAffect(AFFECT_CON);
	RemoveAffect(AFFECT_CHINA_FIREWORK);

	RemoveAffect(SKILL_JEONGWI);
	RemoveAffect(SKILL_GEOMKYUNG);
	RemoveAffect(SKILL_CHUNKEON);
	RemoveAffect(SKILL_EUNHYUNG);
	RemoveAffect(SKILL_GYEONGGONG);
	RemoveAffect(SKILL_GWIGEOM);
	RemoveAffect(SKILL_TERROR);
	RemoveAffect(SKILL_JUMAGAP);
	RemoveAffect(SKILL_MANASHILED);
	RemoveAffect(SKILL_HOSIN);
	RemoveAffect(SKILL_REFLECT);
	RemoveAffect(SKILL_KWAESOK);
	RemoveAffect(SKILL_JEUNGRYEOK);
	RemoveAffect(SKILL_GICHEON);
#ifdef ENABLE_WOLFMAN_CHARACTER
	// ¼öÀÎÁ·(WOLFMEN) ¹öÇÁ Ãß°¡
	RemoveAffect(SKILL_JEOKRANG);
	RemoveAffect(SKILL_CHEONGRANG);
#endif
}

substitute with:


const std::vector<WORD> GoodAffects =
{
	AFFECT_MOV_SPEED,
	AFFECT_ATT_SPEED,

	AFFECT_STR,
	AFFECT_DEX,
	AFFECT_INT,
	AFFECT_CON,

	AFFECT_CHINA_FIREWORK,

	// Body Warrior
	SKILL_JEONGWI, // 3 (Berserk)
	SKILL_GEOMKYUNG, // 4 (Aura of the Sword)

	// Mental Warrior
	SKILL_CHUNKEON, // 19 (Strong Body)

	// Blade-Fight Ninja
	SKILL_EUNHYUNG, // 34 (Stealth)

	// Archery Ninja
	SKILL_GYEONGGONG, // 49 (Feather Walk)

	// Weaponry Sura
	SKILL_GWIGEOM, // 63 (Enchanted Blade)
	SKILL_TERROR, // 64 (Fear)
	SKILL_JUMAGAP, // 65 (Enchanted Armour)

	// Black Magic Sura
	SKILL_MANASHILED, // 79 (Dark Protection)

	// Dragon Force Shaman
	SKILL_HOSIN, // 94 (Blessing)
	SKILL_REFLECT, // 95 (Reflection)
	SKILL_GICHEON, // 96 (Dragon's Strength)

	// Healing Force Shaman
	SKILL_KWAESOK, // 110 (Swiftness)
	SKILL_JEUNGRYEOK, // 111 (Attack Up)

	// Instinct Lykan
	SKILL_JEOKRANG, // 174 (Crimson Wolf Soul)
	SKILL_CHEONGRANG, // 175 (Indigo Wolf Soul)
};

void CHARACTER::RemoveGoodAffect()
{
	for (auto it : GoodAffects)
	{
		const CAffect * pkAff = FindAffect(it);
		if (pkAff)
			RemoveAffect(const_cast<CAffect *>(pkAff), false);
	}

	ComputePoints();
}

 

find:


void CHARACTER::RemoveBadAffect()
{
	sys_log(0, "RemoveBadAffect %s", GetName());
	// µ¶
	RemovePoison();

	RemoveFire();

	// ½ºÅÏ           : Value%·Î »ó´ë¹æÀ» 5ÃÊ°£ ¸Ó¸® À§¿¡ º°ÀÌ µ¹¾Æ°£´Ù. (¶§¸®¸é 1/2 È®·ü·Î Ç®¸²)               AFF_STUN
	RemoveAffect(AFFECT_STUN);

	// ½½·Î¿ì         : Value%·Î »ó´ë¹æÀÇ °ø¼Ó/ÀÌ¼Ó ¸ðµÎ ´À·ÁÁø´Ù. ¼ö·Ãµµ¿¡ µû¶ó ´Þ¶óÁü ±â¼ú·Î »ç¿ë ÇÑ °æ¿ì¿¡   AFF_SLOW
	RemoveAffect(AFFECT_SLOW);

	// Åõ¼Ó¸¶·É
	RemoveAffect(SKILL_TUSOK);

	// ÀúÁÖ
	//RemoveAffect(SKILL_CURSE);

	// ÆĹý¼ú
	//RemoveAffect(SKILL_PABUP);

	// ±âÀý           : Value%·Î »ó´ë¹æÀ» ±âÀý½ÃŲ´Ù. 2ÃÊ                                                       AFF_FAINT
	//RemoveAffect(AFFECT_FAINT);

	// ´Ù¸®¹­ÀÓ       : Value%·Î »ó´ë¹æÀÇ À̵¿¼Óµµ¸¦ ¶³¾îÆ®¸°´Ù. 5ÃÊ°£ -40                                      AFF_WEB
	//RemoveAffect(AFFECT_WEB);

	// Àáµé±â         : Value%·Î »ó´ë¹æÀ» 10ÃÊ°£ ÀáÀç¿î´Ù. (¶§¸®¸é Ç®¸²)                                        AFF_SLEEP
	//RemoveAffect(AFFECT_SLEEP);

	// ÀúÁÖ           : Value%·Î »ó´ë¹æÀÇ °øµî/¹æµî ¸ðµÎ ¶³¾îÆ®¸°´Ù. ¼ö·Ãµµ¿¡ µû¶ó ´Þ¶óÁü ±â¼ú·Î »ç¿ë ÇÑ °æ¿ì¿¡ AFF_CURSE
	//RemoveAffect(AFFECT_CURSE);

	// ¸¶ºñ           : Value%·Î »ó´ë¹æÀ» 4ÃÊ°£ ¸¶ºñ½ÃŲ´Ù.                                                     AFF_PARA
	//RemoveAffect(AFFECT_PARALYZE);

	// ºÎµ¿¹ÚºÎ       : ¹«´ç ±â¼ú
	//RemoveAffect(SKILL_BUDONG);
}

substitute it with:


const std::vector<WORD> BadAffects =
{
	AFFECT_FIRE,
	AFFECT_POISON,

	AFFECT_STUN,
	AFFECT_SLOW,

	SKILL_TUSOK,
};

void CHARACTER::RemoveBadAffect()
{
	for (auto it : BadAffects)
	{
		const CAffect * pkAff = FindAffect(it);
		if (pkAff)
		{
			RemoveAffect(const_cast<CAffect *>(pkAff), false);

			switch (it)
			{
				case AFFECT_FIRE:
					event_cancel(&m_pkFireEvent);
					break;
				case AFFECT_POISON:
					event_cancel(&m_pkPoisonEvent);
					break;
			}
		}
	}

	UpdatePacket();
}

 

 
 
 
 
 
 
 
 
 
 
 
 
 

Done!

Comparison:

  • Like 11
  • Thanks 5

Share this post


Link to post
Share on other sites
2 minutes ago, Dobrescu Sebastian said:

Or you can create a new ClearAffect with new definitions of which affect it should clear on target.

That's not the issue as i said in the topic.

YellowishWideGermanshorthairedpointer

You can create a new function which does the same thing as RemoveAffect but without the computepoints check which is the lag factor, but that's the same thing as i did, I kept things simple.

Share this post


Link to post
Share on other sites
#define IS_FIX_POISON_RISIPA_AFFECT(type) ((type) == AFFECT_MOV_SPEED || (type) == AFFECT_ATT_SPEED || (type) == AFFECT_STR || (type) == AFFECT_DEX || (type) == AFFECT_INT || (type) == AFFECT_CON || (type) == AFFECT_CHINA_FIREWORK || (type) == SKILL_JEONGWI || (type) == SKILL_GEOMKYUNG || (type) == SKILL_CHUNKEON || (type) == SKILL_EUNHYUNG || (type) == SKILL_GYEONGGONG || (type) == SKILL_GWIGEOM || (type) == SKILL_TERROR || (type) == SKILL_JUMAGAP || (type) == SKILL_MANASHILED || (type) == SKILL_HOSIN || (type) == SKILL_REFLECT || (type) == SKILL_KWAESOK || (type) == SKILL_JEUNGRYEOK || (type) == SKILL_GICHEON || (type) == SKILL_JEOKRANG || (type) == SKILL_CHEONGRANG)
void CHARACTER::ClearAffect_New(bool bSave)
{
	TAffectFlag afOld = m_afAffectFlag;
	WORD	wMovSpd = GetPoint(POINT_MOV_SPEED);
	WORD	wAttSpd = GetPoint(POINT_ATT_SPEED);

	itertype(m_list_pkAffect) it = m_list_pkAffect.begin();

	while (it != m_list_pkAffect.end())
	{
		CAffect * pkAff = *it;

		if (bSave)
		{
			if (!IS_FIX_POISON_RISIPA_AFFECT(pkAff->dwType))
			{
				++it;
				continue;
			}
	
			if (IsPC())
			{
				SendAffectRemovePacket(GetDesc(), GetPlayerID(), pkAff->dwType, pkAff->bApplyOn);
			}
		}

		ComputeAffect(pkAff, false);

		it = m_list_pkAffect.erase(it);
		CAffect::Release(pkAff);
	}

	if (afOld != m_afAffectFlag ||
			wMovSpd != GetPoint(POINT_MOV_SPEED) ||
			wAttSpd != GetPoint(POINT_ATT_SPEED))
		UpdatePacket();

	CheckMaximumPoints();

	if (m_list_pkAffect.empty())
		event_cancel(&m_pkAffectEvent);
}

That's how i solved a long time ago. Everyone is free to use what he wants.

In chat skill at sura skill you use 

if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_REMOVE_GOOD_AFFECT))
{
.....
	if (number(1, 100) <= iAmount2)
	{
		pkChrVictim->ClearAffect_New(true);
		pkChrVictim->AddAffect(m_pkSk->dwVnum, POINT_NONE, 0, AFF_PABEOP, iDur2, 0, true);
	}
}

 

  • Thanks 1

Share this post


Link to post
Share on other sites
29 minutes ago, Dobrescu Sebastian said:

 

 
 

Well not much of a difference i guess, i just modified RemoveAffect() in order to behave similiarly.

But yea!

  • Like 1

Share this post


Link to post
Share on other sites

I wouldn't suggest anyone using the ops solution, as it isn't working as intended.
The issue that you don't take into account is, that e.g. a warrior can use "Sword Aura" or use a dew, ... and the shaman can then use heal onto him (which will trigger RefreshAffect() and thus Compute and apply the points for the already existing affect again!)

You should recompute all the players points or refactor the whole affect system (because it is actual garbage) to actually solve this bug.

tl;dr: Replace RefreshAffect() through ComputePoints()

  • Thanks 1

Share this post


Link to post
Share on other sites

^ Tested and the bug iz real. Should refactor the whole affect , because ymir waz fucking lazy to do it right.

Share this post


Link to post
Share on other sites
27 minutes ago, Socialized said:

I wouldn't suggest anyone using the ops solution, as it isn't working as intended.
The issue that you don't take into account is, that e.g. a warrior can use "Sword Aura" or use a dew, ... and the shaman can then use heal onto him (which will trigger RefreshAffect() and thus Compute and apply the points for the already existing affect again!)

You should recompute all the players points or refactor the whole affect system (because it is actual garbage) to actually solve this bug.

tl;dr: Replace RefreshAffect() through ComputePoints()

Thanks for the contribution, done.

10 minutes ago, M.Sorin said:

^ Tested and the bug iz real. Should refactor the whole affect , because ymir waz fucking lazy to do it right.

Not really, the issue is they are recomputing points every time an affect gets removed while they should only do it once at the end of the process, as I said.

The mistake I made was to simply test the normal case, and not the shaman one. Didn't think that refreshaffect would just readd the affect, that's why the bug was occurring. I fixed it.

Share this post


Link to post
Share on other sites
Just now, M.Sorin said:

Yea , i know. But still , ymir was to lazzy to fix some simple things. Not only the affect.

Dunno wether or not this is fixed on official servers yet, but yeah. We have to fix a ton of things ourselves.

 

But isn't this what really makes the difference between servers and developers?

  • Thanks 1

Share this post


Link to post
Share on other sites

Right on point, if you are a good developer , you have a good server. But let`s leave this discuss only for affect things xD.

Share this post


Link to post
Share on other sites
vor 19 Stunden schrieb Syreldar:

Well, this forum is kinda dead, i like to talk about things once in a while, regardless of the main topic.

I agree with that.
Did people move to a different forum or is there a skype group open?

Share this post


Link to post
Share on other sites
5 minutes ago, Socialized said:

I agree with that.
Did people move to a different forum or is there a skype group open?

Nah, I believe people just moved on to better things in life, metin2 is full of leechers, no actual respect for developers.

  • Like 3

Share this post


Link to post
Share on other sites

yep.. i used to contribute here quite often but i'v stopped since few months. since i saw the amount of people leeching and not sharing anything with others 

i have decided to stop. also few people just keep criticizing others work without even understanding how it works just cause they were bored.

 

Right now im working full time as developer(c#) in finance company but i still develop games as hobby and im working on a generic game management system(metin2 included)

that ill be selling in a month or two to public.

 

metin2 is no longer alive as it used to be and that's a fact. one of the biggest reasons for metin2dev to die is because of lack of management(in my opinion).

  • Like 3

Share this post


Link to post
Share on other sites

As i have tested this, i can encounter some type of "errors".

 

If someone uses dispell on me, it doesn't remove my berserk, if he does it the second time, it does remove the berserk, it happens to strong body too, sura's enchanted blade and enchanted armor.

Share this post


Link to post
Share on other sites
1 hour ago, Dr3Ame3r said:

As i have tested this, i can encounter some type of "errors".

 

If someone uses dispell on me, it doesn't remove my berserk, if he does it the second time, it does remove the berserk, it happens to strong body too, sura's enchanted blade and enchanted armor.

Try my fix.

Share this post


Link to post
Share on other sites
2 hours ago, Dr3Ame3r said:

As i have tested this, i can encounter some type of "errors".

 

If someone uses dispell on me, it doesn't remove my berserk, if he does it the second time, it does remove the berserk, it happens to strong body too, sura's enchanted blade and enchanted armor.

You did something wrong, it works fine for everybody here.

Share this post


Link to post
Share on other sites
Acum 1 oră, Syreldar a spus:

You did something wrong, it works fine for everybody here.

Nope, didn't do anything wrong, it just does not work after the removal effect, i've already told you, it happens only on those spells.

I don't think that i am crazy, and  the bug replicates like this:  https://i.gyazo.com/dab8fd646e1c2bccf74278e231aa4932.mp4

b0SqSRVvSk_1Aa5NreuYCA.png

V3BditH5SImCv7XkQaDIpw.png

-ZIFqmwaRNakLjIXQie7AQ.png

dHYd29VdTjm4V1zrdJ_ARw.png

Share this post


Link to post
Share on other sites
8 minutes ago, Dr3Ame3r said:

Nope, didn't do anything wrong, it just does not work after the removal effect, i've already told you, it happens only on those spells.

 

Can you try to add RefreshAffect() before UpdatePacket() on removegoodaffect()?

Share this post


Link to post
Share on other sites
On 2/12/2018 at 9:21 PM, Socialized said:

I wouldn't suggest anyone using the ops solution, as it isn't working as intended.
The issue that you don't take into account is, that e.g. a warrior can use "Sword Aura" or use a dew, ... and the shaman can then use heal onto him (which will trigger RefreshAffect() and thus Compute and apply the points for the already existing affect again!)

You should recompute all the players points or refactor the whole affect system (because it is actual garbage) to actually solve this bug.

tl;dr: Replace RefreshAffect() through ComputePoints()

You don't have to refactor the whole affect system, you can "fix" it with a fix similar to OP's one, just not exactly the same.

 

EDIT: I tried reproducing that bug on my source, but neither the "Sword Aura" nor the "Heal" invokes ComputePoints()

Share this post


Link to post
Share on other sites

my error compile

	char_affect.cpp:771: error: scalar object 'GoodAffects' requires one element in initializer
char_affect.cpp: In member function 'void CHARACTER::RemoveGoodAffect()':
char_affect.cpp:775: error: a function-definition is not allowed here before ':' token
char_affect.cpp:781: error: could not convert 'CHARACTER::RefreshAffect()' to 'bool'
char_affect.cpp:782: error: expected `)' before ';' token
compile input.cpp
char_affect.cpp: At global scope:
char_affect.cpp:740: warning: 'GoodAffects' defined but not used

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
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×