New Feature for Generating Unique Identifiers


Description of Changes:

Extraction of UID Generation

In the previous version of the Create function, UID generation relied on the GetCRC32 function, which was susceptible to collisions. Instead, I opted to use UUID identifiers.

UUID (Universally Unique Identifier) is a randomly generated unique identifier. It is much less prone to collisions than a standard CRC32 string.

Advantages of Using UUID

  • Characters/Monsters retain a consistent unique identification regardless of translations into different languages.
  • UUID remains unchanged even if the format of monster names changes (e.g., adding/removing spaces).

Updated VID Class

The VID class now stores UUID identifiers instead of CRC32.

CRC32 identifiers are generated based on character names and are prone to conflicts if character names are similar. UUID identifiers are randomly generated and always unique.

Type Updates for Argument:

const char * c_pszName ➡️ std::string_view displayName

Required:

Minimum Standard: C++17

Implementation:

📂 File Location: ‘game -> char.cpp’

🔍 Find

void CHARACTER::Create(const char * c_pszName, DWORD vid, bool isPC)
{
	static int s_crc = 172814;

	char crc_string[128+1];
	snprintf(crc_string, sizeof(crc_string), "%s%p%d", c_pszName, this, ++s_crc);
	m_vid = VID(vid, GetCRC32(crc_string, strlen(crc_string)));

	if (isPC)
		m_stName = c_pszName;
}

➕ Add above the new function:

std::optional<VID> CHARACTER::GenerateUniqueID(std::string_view displayName, DWORD vid)
{
	if (displayName.empty())
	{
		return std::nullopt;
	}

	boost::uuids::uuid uuid = boost::uuids::random_generator()();
	sys_log(0, "Generated UUID for %s: %s", displayName.data(), to_string(uuid).c_str());
	return VID(vid, uuid);
}

🔍 Find

void CHARACTER::Create(const char * c_pszName, DWORD vid, bool isPC)
{
	static int s_crc = 172814;

	char crc_string[128+1];
	snprintf(crc_string, sizeof(crc_string), "%s%p%d", c_pszName, this, ++s_crc);
	m_vid = VID(vid, GetCRC32(crc_string, strlen(crc_string)));

	if (isPC)
		m_stName = c_pszName;
}

♻️ Replace

bool CHARACTER::Create(std::string_view displayName, DWORD vid, bool isPC)
{
	if (displayName.empty())
	{
		return false;
	}

	auto uniqueId = GenerateUniqueID(displayName, vid);
	if (!uniqueId)
	{
		return false;
	}

	m_vid = *uniqueId;

	if (isPC)
	{
		m_stName.assign(displayName.begin(), displayName.end());
	}

	return true;
}

📂 File Location: ‘game -> char.h’

🔍 Find

void			Create(const char * c_pszName, DWORD vid, bool isPC);

➕ Add above the new function:

std::optional<VID> GenerateUniqueID(std::string_view displayName, DWORD vid);

🔍 Find

void			Create(const char * c_pszName, DWORD vid, bool isPC);

♻️ Replace

bool Create(std::string_view displayName, DWORD vid, bool isPC);

📂 File Location: ‘game -> vid.h’

🔍 Find

VID() : m_id(0), m_crc(0)
{
}

♻️ Replace

VID() : m_id(0), m_uuid()
{
}

🔍 Find

VID(DWORD id, DWORD crc)
{
	m_id = id;
	m_crc = crc;
}

♻️ Replace

VID(DWORD id, const boost::uuids::uuid& uuid) : m_id(id), m_uuid(uuid)
{
}

🔍 Find

VID(const VID &rvid)
{
	*this = rvid;
}

♻️ Replace

VID(const VID &rvid) : m_id(rvid.m_id), m_uuid(rvid.m_uuid)
{
}

🔍 Find

const VID & operator = (const VID & rhs)
{
	m_id = rhs.m_id;
	m_crc = rhs.m_crc;
	return *this;
}

♻️ Replace

const VID & operator = (const VID & rhs) 
{
	m_id = rhs.m_id;
	m_uuid = rhs.m_uuid;
	return *this;
}

🔍 Find

bool operator == (const VID & rhs) const
{
	return (m_id == rhs.m_id) && (m_crc == rhs.m_crc);
}

♻️ Replace

bool operator == (const VID & rhs) const 
{
	return (m_id == rhs.m_id) && (m_uuid == rhs.m_uuid);
}

🔍 Find

void Reset()
{
	m_id = 0, m_crc = 0;
}

♻️ Replace

void Reset() 
{
	m_id = 0;
	m_uuid = boost::uuids::uuid(); // empty UUID
}

🔍 Find

private:
	DWORD m_id;
	DWORD m_crc;

♻️ Replace

private:
    DWORD m_id;
    boost::uuids::uuid m_uuid; // #uuid

📂 File Location: ‘game -> stdx.h’

➕ Add

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

Share this article
Shareable URL
Prev Post

Fixing Memory Leaks with Smart Pointer Implementation in Message System

Next Post

Mastering PvP Strategies in Metin2

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Read next

Metin2: LoginKey FIX

A banned player could still enter the game using a login key (stored in cache until the db is restarted). This…