INTRODUCTION & PROBLEM
Hello, we will solve the famous "Cannot Find Tree" problem in the "CHARACTER::Sync" function in the server src and also the problems that may be caused by the "Dead();" section used for everything that is not a PC in this function.
WHAT DID WE CHANGE?
All of the currently shared fixes are actually incomplete, we will make a new arrangement to solve this problem at its root, thus we will fix the problem completely.
HOW TO DO?
Without going into details such as editing the reward mechanism of the existing dead function, we will simply create a new dead function and use it in Sync. The main purpose of this function, which can only be used for mobs and metins, is that it does not give a reward (drop) after the dead function, let's get started.
UPDATE - 23/10/2024
I fixed a code that caused the (!new_tree) part of the function to return false under all circumstances also added all the nullptr checks and extra sys_err messages where necessary, expanded the content of the existing sys_err messages, these changes will not cause any performance disadvantages and there is no possibility of it being misused in any way anymore, please use the final version.
First, open "char_battle.cpp"
- // FIND;
- struct FuncSetLastAttacked
- // Add ABOVE;
- void CHARACTER::RewardlessDead() // DevFix 29
- {
- if (IsPC()) // This function only for mobs or stones, so if IsPC() has triggered this, redirect it regular Dead() function. - [MT2Dev Note] - 18/10/2024
- {
- sys_log (0, "<CHARACTER::RewardlessDead> Wrong Usage! It was a PC, redirect it to regular Dead()");
- Dead(); // Just to prevent, not needed if you use it properly. - [Mitachi] - 18/10/2024
- return;
- }
- if (IsDead())
- {
- return;
- }
- if (IsMonster() || IsStone()) // Dead is only possible when victim is mob or stone. - [MT2Dev Note] - 10/10/2024
- {
- m_dwKillerPID = 0; // Remove the killer to avoid quest triggers may in dead. - [Mitachi] - 18/10/2024
- SET_BIT (m_pointsInstant.instant_flag, INSTANT_FLAG_NO_REWARD); // Set no reward. - [Mitachi] - 18/10/2024
- SetPosition (POS_DEAD);
- ClearAffect (true);
- ClearSync();
- if (m_pkStunEvent)
- {
- event_cancel (&m_pkStunEvent);
- }
- TPacketGCDead pack;
- pack.header = HEADER_GC_DEAD;
- pack.vid = m_vid;
- PacketAround (&pack, sizeof (pack));
- REMOVE_BIT (m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
- sys_log (0, "Rewardless_DEAD: %s %p", GetName(), this);
- // Create Dead event.. In the Dead event, for monsters, make them destroy after a few seconds. - [Ymir Dev Note]
- if (m_pkDeadEvent)
- {
- event_cancel (&m_pkDeadEvent);
- }
- if (IsStone())
- {
- ClearStone();
- }
- if (GetDungeon())
- {
- GetDungeon()->DeadCharacter (this);
- }
- SCharDeadEventInfo* pEventInfo = AllocEventInfo<SCharDeadEventInfo>();
- pEventInfo->isPC = false;
- pEventInfo->dwID = this->GetVID();
- m_pkDeadEvent = event_create (dead_event, pEventInfo, PASSES_PER_SEC (0));
- sys_log (0, "Rewardless_DEAD_EVENT_CREATE: %s %p %p", GetName(), this, get_pointer (m_pkDeadEvent));
- }
- }
Then open "char.cpp"
- // Find;
- bool CHARACTER::Sync (long x, long y)
- // Change the function;
- // DevFix 29 - Necessary arrangement for scenarios where sync is not possible. - [MT2Dev Note] - 01/04/2024
- // Moves to the specified x, y position regardless. - [Ymir Dev Note]
- bool CHARACTER::Sync (long x, long y)
- {
- LPSECTREE current_tree = GetSectree(); // For a better performance, call it only once.. - [MT2Dev Note]
- if (!current_tree)
- {
- sys_err ("<CHARACTER::Sync> Sectree is NULL!");
- return false;
- }
- if (IsPC() && IsDead()) // DevFix 27 - Dead players not needed sync.. - [MT2Dev Note] - 01/04/2024
- {
- return false;
- }
- LPSECTREE new_tree = SECTREE_MANAGER::instance().Get (GetMapIndex(), x, y);
- if (!new_tree)
- {
- if (GetDesc())
- {
- sys_err ("No Tree: (x: %ld) (y: %ld) (Name: %s) (Map: %d)", x, y, GetName(), GetMapIndex()); // Added map index. - [MT2Dev Note] - 23/10/2024
- x = GetX();
- y = GetY();
- new_tree = current_tree; // If there is no new tree, just use the old one. - [MT2Dev Note]
- if (!new_tree)
- {
- sys_err ("[CRITICAL!!] - No Tree: (x: %ld) (y: %ld) (Name: %s) (Map: %d)", x, y, GetName(), GetMapIndex()); // Added map index. - [MT2Dev Note] - 23/10/2024
- GetDesc()->SetPhase (PHASE_CLOSE);
- return false; // Set the new_tree, call that a "fix" and forget one f**in line that cause return it false, hi there it's MT2Dev -_-
- }
- }
- else
- {
- if (IsMonster() || IsStone()) // Dead is only possible when victim is mob or stone. - [MT2Dev Note] - 10/10/2024
- {
- sys_err ("[MOB or STONE]No Tree: (x: %ld) (y: %ld) (Map: %d)", x, y, GetMapIndex());
- RewardlessDead(); // In this case, we don't want any reward so this is new function for it. - [MT2Dev Note] - 10/10/2024
- return false;
- }
- else
- {
- sys_err ("[POTENTIAL HACK!]No Tree: (x: %ld) (y: %ld) (Map: %d)", x, y, GetMapIndex());
- return false;
- }
- }
- }
- SetRotationToXY (x, y);
- SetXYZ (x, y, 0);
- // Under that, you will see some kind a unnecesary nullptr controls, this ones for ensure everything is correct.
- // This ones will not chance anything about performance in new compilers, so that ones don't hurt anyone i guess. - [MT2Dev Note] - 23/10/2024
- if (GetDungeon())
- {
- if (new_tree)
- {
- // Dungeon event attribute change. - [Ymir Dev Note]
- int iLastEventAttr = m_iEventAttr;
- m_iEventAttr = new_tree->GetEventAttribute (x, y);
- if (m_iEventAttr != iLastEventAttr)
- {
- if (GetParty())
- {
- quest::CQuestManager::instance().AttrOut (GetParty()->GetLeaderPID(), this, iLastEventAttr);
- quest::CQuestManager::instance().AttrIn (GetParty()->GetLeaderPID(), this, m_iEventAttr);
- }
- else
- {
- quest::CQuestManager::instance().AttrOut (GetPlayerID(), this, iLastEventAttr);
- quest::CQuestManager::instance().AttrIn (GetPlayerID(), this, m_iEventAttr);
- }
- }
- }
- else
- {
- sys_err ("[POTENTIAL HACK!] Dungeon - There is no new tree!");
- return false;
- }
- }
- if (current_tree != new_tree)
- {
- if (!IsNPC())
- {
- if (current_tree && new_tree)
- {
- SECTREEID id = new_tree->GetID();
- SECTREEID old_id = current_tree->GetID();
- const float fDist = DISTANCE_SQRT (id.coord.x - old_id.coord.x, id.coord.y - old_id.coord.y);
- sys_log (0, "SECTREE DIFFER: %s %dx%d was %dx%d dist %.1fm", GetName(), id.coord.x, id.coord.y, old_id.coord.x, old_id.coord.y, fDist); // DevFix 30
- }
- else
- {
- sys_err ("[POTENTIAL HACK!] There is no current tree or new tree!");
- return false;
- }
- }
- if (new_tree)
- {
- new_tree->InsertEntity (this);
- }
- else
- {
- sys_err ("[POTENTIAL HACK!] InsertEntity NOT possible because there is no new tree!");
- return false;
- }
- }
- return true;
- }
Lastly, open "char.h"
Best regards, MT2Dev.