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>