Jump to content

[M2Dev] Advanced Files To Build Your Server: Src & Server Files & Client [x64 / DX9Ex / CMake / Python3.14 / FreeType / XChaCha20-Poly1305]


Recommended Posts

5 hours ago, .Toaster said:

I tried both solutions, but unfortunately neither of them worked. I still can’t see any objects on the map.

Okay i´ve fixxed it even if i dont know if its good like this but it works for me

Replaced:

bool CProperty::ReadFromMemory(const void * c_pvData, int iLen, const char * c_pszFileName)
{
	const char * pcData = (const char *) c_pvData;

	if (*(DWORD *) pcData != MAKEFOURCC('Y', 'P', 'R', 'T'))
		return false;

	pcData += sizeof(DWORD);

	if (*pcData != '\r' || *(pcData + 1) != '\n')
	{
		TraceError("CProperty::ReadFromMemory: File format error after FourCC: %s\n", c_pszFileName);
		return false;
	}

	pcData += 2;

	CTokenVector stTokenVector;
/*
	char szTimeStamp[64];
	memcpy(szTimeStamp, pcData, 14);
	szTimeStamp[14] = '\0';
	pcData += 14;

 	if (*pcData != '\r' || *(pcData + 1) != '\n')
	{
		TraceError("CProperty::ReadFromMemory: File format error after TimeStamp: %s\n", c_pszFileName);
		return false;
	}

	std::string m_stTimeStamp;
	
	m_stTimeStamp = szTimeStamp;

	int iTimeStampLen = 14 + _snprintf(szTimeStamp + 14, 64 - 14, "%s", mc_pFileName);
	m_dwCRC = GetCRC32(szTimeStamp, iTimeStampLen);

	char tmp[64];
	sprintf(tmp, "%u", m_dwCRC);
	m_stCRC.assign(tmp);

	CMemoryTextFileLoader textFileLoader;
	textFileLoader.Bind(iLen - (sizeof(DWORD) + 2 + 14 + 2), pcData);

	for (DWORD i = 0; i < textFileLoader.GetLineCount(); ++i)
	{
		if (!textFileLoader.SplitLine(i, &stTokenVector))
			continue;

		stl_lowers(stTokenVector[0]);
		std::string stKey = stTokenVector[0];

		stTokenVector.erase(stTokenVector.begin());
		PutVector(stKey.c_str(), stTokenVector);
	}
	return true;
	*/
	CMemoryTextFileLoader textFileLoader;
	textFileLoader.Bind(iLen - (sizeof(DWORD) + 2), pcData);

	m_stCRC = textFileLoader.GetLineString(0);
	m_dwCRC = atoi(m_stCRC.c_str());

	for (DWORD i = 1; i < textFileLoader.GetLineCount(); ++i)
	{
		if (!textFileLoader.SplitLine(i, &stTokenVector))
			continue;

		stl_lowers(stTokenVector[0]);
		std::string stKey = stTokenVector[0];

		stTokenVector.erase(stTokenVector.begin());
		PutVector(stKey.c_str(), stTokenVector);
	}

	//Tracef("Property: %s\n", c_pszFileName);
	return true;
}


With: 

bool CProperty::ReadFromMemory(const void * c_pvData, int iLen, const char * c_pszFileName)
{
    const char* pStart = (const char*)c_pvData;
    const char* pcData = pStart;
  
    if (*(DWORD *) pcData != MAKEFOURCC('Y', 'P', 'R', 'T'))
        return false;

    pcData += sizeof(DWORD);

   
    while (pcData < pStart + iLen && (*pcData == '\r' || *pcData == '\n' || *pcData == ' ' || *pcData == '\t'))
        ++pcData;

   
    int textLen = iLen - int(pcData - pStart);
    if (textLen <= 0)
    {
        TraceError("CProperty::ReadFromMemory: textLen <= 0 in %s\n", c_pszFileName);
        return false;
    }

    CTokenVector stTokenVector;

    
    CMemoryTextFileLoader textFileLoader;
    textFileLoader.Bind(textLen, pcData);

    m_stCRC.clear();
    m_dwCRC = 0;

    
    if (textFileLoader.GetLineCount() > 0)
    {
        m_stCRC = textFileLoader.GetLineString(0);

        bool bAllDigits = !m_stCRC.empty() && std::all_of(m_stCRC.begin(), m_stCRC.end(), [](char c)
        {
            return isdigit((unsigned char)c);
        });

        DWORD startLine = 0;

        if (bAllDigits)
        {
            m_dwCRC = atoi(m_stCRC.c_str());
            startLine = 1; 
        }

        for (DWORD i = startLine; i < textFileLoader.GetLineCount(); ++i)
        {
            if (!textFileLoader.SplitLine(i, &stTokenVector))
                continue;

            stl_lowers(stTokenVector[0]);
            std::string stKey = stTokenVector[0];

            stTokenVector.erase(stTokenVector.begin());
            PutVector(stKey.c_str(), stTokenVector);
        }
    }

    return true;
}

 

  • Good 1
  • Active+ Member
15 hours ago, .Toaster said:

Okay i´ve fixxed it even if i dont know if its good like this but it works for me

Replaced:

bool CProperty::ReadFromMemory(const void * c_pvData, int iLen, const char * c_pszFileName)
{
	const char * pcData = (const char *) c_pvData;

	if (*(DWORD *) pcData != MAKEFOURCC('Y', 'P', 'R', 'T'))
		return false;

	pcData += sizeof(DWORD);

	if (*pcData != '\r' || *(pcData + 1) != '\n')
	{
		TraceError("CProperty::ReadFromMemory: File format error after FourCC: %s\n", c_pszFileName);
		return false;
	}

	pcData += 2;

	CTokenVector stTokenVector;
/*
	char szTimeStamp[64];
	memcpy(szTimeStamp, pcData, 14);
	szTimeStamp[14] = '\0';
	pcData += 14;

 	if (*pcData != '\r' || *(pcData + 1) != '\n')
	{
		TraceError("CProperty::ReadFromMemory: File format error after TimeStamp: %s\n", c_pszFileName);
		return false;
	}

	std::string m_stTimeStamp;
	
	m_stTimeStamp = szTimeStamp;

	int iTimeStampLen = 14 + _snprintf(szTimeStamp + 14, 64 - 14, "%s", mc_pFileName);
	m_dwCRC = GetCRC32(szTimeStamp, iTimeStampLen);

	char tmp[64];
	sprintf(tmp, "%u", m_dwCRC);
	m_stCRC.assign(tmp);

	CMemoryTextFileLoader textFileLoader;
	textFileLoader.Bind(iLen - (sizeof(DWORD) + 2 + 14 + 2), pcData);

	for (DWORD i = 0; i < textFileLoader.GetLineCount(); ++i)
	{
		if (!textFileLoader.SplitLine(i, &stTokenVector))
			continue;

		stl_lowers(stTokenVector[0]);
		std::string stKey = stTokenVector[0];

		stTokenVector.erase(stTokenVector.begin());
		PutVector(stKey.c_str(), stTokenVector);
	}
	return true;
	*/
	CMemoryTextFileLoader textFileLoader;
	textFileLoader.Bind(iLen - (sizeof(DWORD) + 2), pcData);

	m_stCRC = textFileLoader.GetLineString(0);
	m_dwCRC = atoi(m_stCRC.c_str());

	for (DWORD i = 1; i < textFileLoader.GetLineCount(); ++i)
	{
		if (!textFileLoader.SplitLine(i, &stTokenVector))
			continue;

		stl_lowers(stTokenVector[0]);
		std::string stKey = stTokenVector[0];

		stTokenVector.erase(stTokenVector.begin());
		PutVector(stKey.c_str(), stTokenVector);
	}

	//Tracef("Property: %s\n", c_pszFileName);
	return true;
}


With: 

bool CProperty::ReadFromMemory(const void * c_pvData, int iLen, const char * c_pszFileName)
{
    const char* pStart = (const char*)c_pvData;
    const char* pcData = pStart;
  
    if (*(DWORD *) pcData != MAKEFOURCC('Y', 'P', 'R', 'T'))
        return false;

    pcData += sizeof(DWORD);

   
    while (pcData < pStart + iLen && (*pcData == '\r' || *pcData == '\n' || *pcData == ' ' || *pcData == '\t'))
        ++pcData;

   
    int textLen = iLen - int(pcData - pStart);
    if (textLen <= 0)
    {
        TraceError("CProperty::ReadFromMemory: textLen <= 0 in %s\n", c_pszFileName);
        return false;
    }

    CTokenVector stTokenVector;

    
    CMemoryTextFileLoader textFileLoader;
    textFileLoader.Bind(textLen, pcData);

    m_stCRC.clear();
    m_dwCRC = 0;

    
    if (textFileLoader.GetLineCount() > 0)
    {
        m_stCRC = textFileLoader.GetLineString(0);

        bool bAllDigits = !m_stCRC.empty() && std::all_of(m_stCRC.begin(), m_stCRC.end(), [](char c)
        {
            return isdigit((unsigned char)c);
        });

        DWORD startLine = 0;

        if (bAllDigits)
        {
            m_dwCRC = atoi(m_stCRC.c_str());
            startLine = 1; 
        }

        for (DWORD i = startLine; i < textFileLoader.GetLineCount(); ++i)
        {
            if (!textFileLoader.SplitLine(i, &stTokenVector))
                continue;

            stl_lowers(stTokenVector[0]);
            std::string stKey = stTokenVector[0];

            stTokenVector.erase(stTokenVector.begin());
            PutVector(stKey.c_str(), stTokenVector);
        }
    }

    return true;
}

 

GJ man I hope that's the fix cause I've been hearing about this issue a long time now. It's very important that you test things around this and make sure you didn't cause something else and that your fix works perfectly fine. I would love to see other people trying out this fix and give some feedback. I cannot test it since I never had this issue but if that's a legit fix I think you should PR it once testing is done! 🙂

On 11/23/2025 at 1:27 PM, DerUranov97 said:

It’s a solid foundation for a clean project.

I’ve been working with it for a few days now, and thanks to 64-bit and DX9Ex, completely new shader possibilities are opening up.

Maybe yes, but the fact is that I can instantly list and point out 80+ things that need fixing, and that’s many hours of work. It doesn’t seem worthwhile to build on something this old. Unfortunately, the TMP4 sources weren’t a very good choice if you really mean this seriously. The problem is that I would gladly contribute, but before we’d get to any usable version, you’d end up patching GitHub a hundred times a day.

 

Edited by Filachilla
  • Good 1
  • Love 1
  • Active Member
1 hour ago, Filachilla said:

Maybe yes, but the fact is that I can instantly list and point out 80+ things that need fixing, and that’s many hours of work. It doesn’t seem worthwhile to build on something this old. Unfortunately, the TMP4 sources weren’t a very good choice if you really mean this seriously. The problem is that I would gladly contribute, but before we’d get to any usable version, you’d end up patching GitHub a hundred times a day.

 

I would not say that.
It looks really playable at the moment.

Iam planning on starting a test-server with this src as base.
And then disable most of the features and enable them step by step while fixing them.

  • Love 3
1 hour ago, Filachilla said:

Maybe yes, but the fact is that I can instantly list and point out 80+ things that need fixing, and that’s many hours of work. It doesn’t seem worthwhile to build on something this old. Unfortunately, the TMP4 sources weren’t a very good choice if you really mean this seriously. The problem is that I would gladly contribute, but before we’d get to any usable version, you’d end up patching GitHub a hundred times a day.

 

It is also said that it is not a build for everyone. It takes a lot of work, yes, but a project should be built from the ground up.
You should know what you have changed and added; git is your friend. 
I am currently running the source with 1000 player bots, and it has been running really well for 5 days without any memory leaks.

  • Love 4
On 11/28/2025 at 10:42 PM, .Toaster said:

Okay i´ve fixxed it even if i dont know if its good like this but it works for me

Replaced:

bool CProperty::ReadFromMemory(const void * c_pvData, int iLen, const char * c_pszFileName)
{
	const char * pcData = (const char *) c_pvData;

	if (*(DWORD *) pcData != MAKEFOURCC('Y', 'P', 'R', 'T'))
		return false;

	pcData += sizeof(DWORD);

	if (*pcData != '\r' || *(pcData + 1) != '\n')
	{
		TraceError("CProperty::ReadFromMemory: File format error after FourCC: %s\n", c_pszFileName);
		return false;
	}

	pcData += 2;

	CTokenVector stTokenVector;
/*
	char szTimeStamp[64];
	memcpy(szTimeStamp, pcData, 14);
	szTimeStamp[14] = '\0';
	pcData += 14;

 	if (*pcData != '\r' || *(pcData + 1) != '\n')
	{
		TraceError("CProperty::ReadFromMemory: File format error after TimeStamp: %s\n", c_pszFileName);
		return false;
	}

	std::string m_stTimeStamp;
	
	m_stTimeStamp = szTimeStamp;

	int iTimeStampLen = 14 + _snprintf(szTimeStamp + 14, 64 - 14, "%s", mc_pFileName);
	m_dwCRC = GetCRC32(szTimeStamp, iTimeStampLen);

	char tmp[64];
	sprintf(tmp, "%u", m_dwCRC);
	m_stCRC.assign(tmp);

	CMemoryTextFileLoader textFileLoader;
	textFileLoader.Bind(iLen - (sizeof(DWORD) + 2 + 14 + 2), pcData);

	for (DWORD i = 0; i < textFileLoader.GetLineCount(); ++i)
	{
		if (!textFileLoader.SplitLine(i, &stTokenVector))
			continue;

		stl_lowers(stTokenVector[0]);
		std::string stKey = stTokenVector[0];

		stTokenVector.erase(stTokenVector.begin());
		PutVector(stKey.c_str(), stTokenVector);
	}
	return true;
	*/
	CMemoryTextFileLoader textFileLoader;
	textFileLoader.Bind(iLen - (sizeof(DWORD) + 2), pcData);

	m_stCRC = textFileLoader.GetLineString(0);
	m_dwCRC = atoi(m_stCRC.c_str());

	for (DWORD i = 1; i < textFileLoader.GetLineCount(); ++i)
	{
		if (!textFileLoader.SplitLine(i, &stTokenVector))
			continue;

		stl_lowers(stTokenVector[0]);
		std::string stKey = stTokenVector[0];

		stTokenVector.erase(stTokenVector.begin());
		PutVector(stKey.c_str(), stTokenVector);
	}

	//Tracef("Property: %s\n", c_pszFileName);
	return true;
}


With: 

bool CProperty::ReadFromMemory(const void * c_pvData, int iLen, const char * c_pszFileName)
{
    const char* pStart = (const char*)c_pvData;
    const char* pcData = pStart;
  
    if (*(DWORD *) pcData != MAKEFOURCC('Y', 'P', 'R', 'T'))
        return false;

    pcData += sizeof(DWORD);

   
    while (pcData < pStart + iLen && (*pcData == '\r' || *pcData == '\n' || *pcData == ' ' || *pcData == '\t'))
        ++pcData;

   
    int textLen = iLen - int(pcData - pStart);
    if (textLen <= 0)
    {
        TraceError("CProperty::ReadFromMemory: textLen <= 0 in %s\n", c_pszFileName);
        return false;
    }

    CTokenVector stTokenVector;

    
    CMemoryTextFileLoader textFileLoader;
    textFileLoader.Bind(textLen, pcData);

    m_stCRC.clear();
    m_dwCRC = 0;

    
    if (textFileLoader.GetLineCount() > 0)
    {
        m_stCRC = textFileLoader.GetLineString(0);

        bool bAllDigits = !m_stCRC.empty() && std::all_of(m_stCRC.begin(), m_stCRC.end(), [](char c)
        {
            return isdigit((unsigned char)c);
        });

        DWORD startLine = 0;

        if (bAllDigits)
        {
            m_dwCRC = atoi(m_stCRC.c_str());
            startLine = 1; 
        }

        for (DWORD i = startLine; i < textFileLoader.GetLineCount(); ++i)
        {
            if (!textFileLoader.SplitLine(i, &stTokenVector))
                continue;

            stl_lowers(stTokenVector[0]);
            std::string stKey = stTokenVector[0];

            stTokenVector.erase(stTokenVector.begin());
            PutVector(stKey.c_str(), stTokenVector);
        }
    }

    return true;
}

 

So my fix goes like this first run the script im sharing in the *assets* folder after run the client and the remaning errors are corupted files and needed to be replaced from other client recomanded the tmp4 original client and after evrything should be error free ❤️ (for the grapichs in game not showing buildings props and trees )

This is the hidden content, please

  • Metin2 Dev 13
  • Good 3
  • Love 7
  • Honorable Member
16 hours ago, Filachilla said:

Maybe yes, but the fact is that I can instantly list and point out 80+ things that need fixing, and that’s many hours of work. It doesn’t seem worthwhile to build on something this old. Unfortunately, the TMP4 sources weren’t a very good choice if you really mean this seriously. The problem is that I would gladly contribute, but before we’d get to any usable version, you’d end up patching GitHub a hundred times a day.

 

My point here was never to fix Metin2 bugs or implement features. Only to modernize backend things and make it a standard that people use CMake and has a well organized work environment.

This project is intended for people who wants to learn and put their own effort into building something.
Also, as I pointed out in the original post: contributions are welcome. If someone wants to fix old Mt2 bugs, make a PR.

  • Love 3

992404397646696589.png
Former C++ Developer at Gameloft on DML
Join my Discord: Distraught Labs

Hi all,

There is an error in the account.sql file that prevents the import of the account database. Specifically, if you look at the entry with id=2, you will notice a syntax issue:


(1,'admin','*CC67043C7BCFF5EEA5566BD9B1F3C74FD9A5CF5D','1234567','','0000-00-00 00:00:00',0,'OK',0,0,0,
(2,   'test','*CC67043C7BCFF5EEA5566BD9B1F3C74FD9A5CF5D','1234567','','0000-00-00 00:00:00',0,'OK','',0,0,0,

The problem is with the entry for id=2, where there is an inconsistency in the number or type of values (for example, an empty string '' where a number or zero might be expected).

I encountered another error (an IndentationError) in Python script perms.py, and after some investigation, I found that the root cause was improper indentation inside an else block.

if os.name == "nt":
    print(f"Skipped setting Unix permissions on Windows for: {os.path.basename(path)}.")
else:
# <-- code here is not indented properly
permission_code = 0o777

Thank you very much for your work!

 

Edited by ErLullo
Added new error
  • Good 1
  • Love 4
On 12/2/2025 at 8:21 AM, ErLullo said:

Hi all,

There is an error in the account.sql file that prevents the import of the account database. Specifically, if you look at the entry with id=2, you will notice a syntax issue:


(1,'admin','*CC67043C7BCFF5EEA5566BD9B1F3C74FD9A5CF5D','1234567','','0000-00-00 00:00:00',0,'OK',0,0,0,
(2,   'test','*CC67043C7BCFF5EEA5566BD9B1F3C74FD9A5CF5D','1234567','','0000-00-00 00:00:00',0,'OK','',0,0,0,

The problem is with the entry for id=2, where there is an inconsistency in the number or type of values (for example, an empty string '' where a number or zero might be expected).

I encountered another error (an IndentationError) in Python script perms.py, and after some investigation, I found that the root cause was improper indentation inside an else block.

if os.name == "nt":
    print(f"Skipped setting Unix permissions on Windows for: {os.path.basename(path)}.")
else:
# <-- code here is not indented properly
permission_code = 0o777

Thank you very much for your work!

 

I recommend using the original TMP4 client (except for root or compare changes), and the same applies to the entire server (share, locale // data / map, etc.) and the database. Ideally, it would be best to start using InnoDB. If there is interest, I could upload RAW tables for the database without any conflict with optimization.

@ Distraught:

I agree with you, but on the other hand it seems quite counterproductive to me, because we’re basically going in circles… Every now and then a new SF comes out and you’re essentially putting it together like a mosaic, which is why people quickly lose interest in these things. Ideally, it would really be best to get involved in a way that the backend is built on something that isn’t harmful.

By the way, what do you think about Python 3? There’s currently a Python 3 port for the TMP4 client on the forum — I tested it with this release, it has some quirks, but considering what you wrote and your vision, I think it would make sense. Don’t you think?

5 minutes ago, DasSchwarzeTv2 said:

Do you use WSL to compile server & client source? With cross-compilation for windows?

I personally use FreeBSD 14.3 with KDE6 (Plasma 6) and I managed to compile the cross client and run it through Wine without any problems. As for the server, since it's FreeBSD as the native system where Metin has always worked, I didn’t touch it — I compile the server normally. In any case, I have to point out that it's a clean laboratory setup; I really had to tinker with it for a very long time.
However, as a benefit I can say that this results in a nice, clean system with all the advantages of FreeBSD and the overall possibility of completely breaking away from Windows.

At the same time, I don’t recommend WSL because you have limited access to the hardware. For me, it was the right choice considering that I also use AI and various things like ESRGAN, so it made sense to create something where I can compile and run the server, compile and run the client, and still have everything else working.
Anyway, as I said, it took me a lot of hours just to get it running at all.
The hardware used was a Ryzen 7 7435HS and an RTX 4060.

2 hours ago, Filachilla said:

I personally use FreeBSD 14.3 with KDE6 (Plasma 6) and I managed to compile the cross client and run it through Wine without any problems. As for the server, since it's FreeBSD as the native system where Metin has always worked, I didn’t touch it — I compile the server normally. In any case, I have to point out that it's a clean laboratory setup; I really had to tinker with it for a very long time.
However, as a benefit I can say that this results in a nice, clean system with all the advantages of FreeBSD and the overall possibility of completely breaking away from Windows.

At the same time, I don’t recommend WSL because you have limited access to the hardware. For me, it was the right choice considering that I also use AI and various things like ESRGAN, so it made sense to create something where I can compile and run the server, compile and run the client, and still have everything else working.
Anyway, as I said, it took me a lot of hours just to get it running at all.
The hardware used was a Ryzen 7 7435HS and an RTX 4060.

That means everybody is still developing in VMs? Cannot imagine that tbh

gg

try

On 23/08/2025 at 01:03, Distraught said:

Ciao a tutti,

Di recente ho deciso di iniziare a sviluppare una serie di file puliti e modernizzati che sono:

  • Facile da usare
  • Non avere dipendenze esterne
  • Lavora subito con CMake

Per la base ho utilizzato le sorgenti e il client originariamente rilasciati da@ TMP4e ho apportato diverse modifiche per semplificare e modernizzare la configurazione .

🔧Cosa è incluso

  • Completamente compatibile con CMake (non c'è bisogno di pkg o vcpkg).
  • Tutte le dipendenze esterne sono contenute all'interno del progetto:
    • cartella del fornitore → dipendenze create con il progetto
    • includi cartella → librerie solo intestazione
  • 64 bit
  • La build del client utilizza DirectX9 Ex

 

🚀 Iniziare

Server

Repo:

Contenuto nascosto

  • Commenta questo post per vedere il contenuto nascosto.

 

  1. Clonare il repository.
  2. Esegui install.py -> creerà automaticamente le cartelle dei canali richiesti
  3. È possibile configurare gli indici delle mappe per canale all'interno di channels.py

Fonti del server

Repo: 

Contenuto nascosto

  • Commenta questo post per vedere il contenuto nascosto.

 



		

In base alla configurazione, verrà generata la soluzione o i makefile.

Fonti del cliente

Repo: 

Contenuto nascosto

  • Commenta questo post per vedere il contenuto nascosto.

 



		

Per una base clienti compatibile, puoi utilizzare questo repository: 

Contenuto nascosto

  • Commenta questo post per vedere il contenuto nascosto.

 

Caratteristiche principali

  • x64
  • DirectX 9 Ex
  • rendering di testo in batch
  • festa globale
  • decoratori di effetti rimossi
  • migliore pooling della memoria
  • rilevatore modalità display rimosso
  • rilevamento automatico MSAA
  • DeVIL -> stb_image
  • nessuna DLL, tutte le librerie sono statiche
  • WebView2 per browser incorporato
  • Deformazione della mesh SSE2
  • nuovo sistema audio: Miles -> MiniAudio
  • nuovo sistema di pacchetti personalizzati che utilizza ZSTD (compressione) e Camellia (crittografia)
  • spdlog utilizzato per la registrazione

 

Collaboratori

 

Piccola guida da@ Helia01 come configurare un MariaDB:

ok

I changelog sono disponibili direttamente nei messaggi di commit. Pubblicherò regolarmente aggiornamenti. Consiglio di effettuare il pull del repository di tanto in tanto per rimanere aggiornati.

 Non aggiungerò nuove funzionalità. Mi concentrerò esclusivamente sulla riscrittura, pulizia e modernizzazione del codice esistente.

I contributi sono benvenuti! Se vuoi collaborare e dare il tuo contributo nel tuo tempo libero, sentiti libero di unirti a noi.

 

  • Love 1
  • Active+ Member

New PR requests submitted

These PR requests include client and server sources and they are re-constructing the way that CMake configuration works.

 

Introducing Git Submodules:

Git submodules are "repos within repos". The new system uses a Python script upon running

cmake -S . -B build

to automatically download all vendors and includes from their respective Github repos, place each file in the correct folder, delete the downloaded repos that are not required to exist as a repo (for example only the 2 header files from STB Image are copied into include folder, the rest of the downloaded repo is discarded)

Disabled by default, MUST BE ENABLED

 

New structure for include, extern/include and vendor folders in both projects (example):

Was: /vendor/spdlog-1.15.7

New: /vendor/legacy/spdlog-1.15.7, /vendor/latest/spdlog

 

Client source:

The following includes are NOT being updated by the script and remain in include/common:

  • SpeedTreeRT
  • DirectX 9 EX (and relevant headers)
  • Python
  • Anything that is close-sourced or cannot be implemented in the latest version

 

How to choose:

I know that most people don't like change, new versions, familiar feels safer, or simply don't want to bother testing and getting involved with updated libs.

Nothing is changed by default. By running:
 

cmake -S . -B build

everything remains as you know it, with the vendors and includes you've been using so far.

In order to use the latest versions, simply:
 

cmake -S . -B build -DUSE_LEGDEPS=OFF

for a one-time off, or set this option to ON in the root CMakeLists.txt, so you won't have to include it every time in the CMake command.

 

Can I rollback to a custom version of a dependency?

YES! By setting the submodule's versio, adding and committing (locally), your configuration uses now the selected version. You must manually specified the latest (or another) version to abort this. Commands (with Crypto++ as an example):

 > git -C vendor/latest/cryptopp checkout v8.6.0
 > git add vendor/latest/cryptopp
 > git commit -m "Upgrade Cryptopp to v8.6.0 just because I can!"
 > cmake -S . -B build

 

Tested with both options, builds and runs smoothly.

 

Server source:

All includes and vendors are updatable!

How to choose:

I know that most people don't like change, new versions, familiar feels safer, or simply don't want to bother testing and getting involved with updated libs.

Nothing is changed by default. By running:
 

cmake -S . -B build

everything remains as you know it, with the vendors and includes you've been using so far.

In order to use the latest versions, simply:
 

cmake -S . -B build -DUSE_LEGDEPS=OFF

for a one-time off, or set this option to ON in the root CMakeLists.txt, so you won't have to include it every time in the CMake command.

 

 

 HIGHLY EXPERIMENTAL!

[NEW] SIL (System Installed Libaries - FreeBSD ONLY!)

With SIL=ON you

  • Ensure latest version dependencies (like with LEGDEPS=OFF)
  • Source builds FASTER!
    • Spdlog:                                  -1% of the build
    • MariaDB Connector C :        -18% of the build
    • Crypto++ (coming soon):    -30% of the build

Use cmake -S . -B build -DUSE_SIL=ON to completely ignore includes and vendors in the project's directory and instead use:

  • /usr/local/include</XX> for Includes
  • /usr/local/lib for libraries

Requirement: included ports must be installed in order to use this

Verify if a port is installed with

#pkg info <port>
 > pkg info spdlog

If no information about your selected port are shown, install it (port method is highly recommended)

# Find it first
 > whereis spdlog
 > cd /usr/ports/devel/spdlog
 > make install clean

Find all required ports in the root CMakeLists.txt

 

When SIL is ON, LEGDEPS=ON is automatically ignored, ensuring the latest versions are used, READ MORE BELOW 👇👇👇

⚠️ Caveats:

  • Crypto++ is EXCLUDED from SIL. Why??? Crypto++ version > 8.7.0 is incompatible when not built with CMake. When SIL is ON, CMake is being built from vendor/latest/cryptopp as usual. Attempts to include /usr/local/lib/libcryptopp.a caused auth channel crashes, Handshake process infinite loops, client login screen getting stuck to "Connecting to server..." message.
    If you have some experience and wanna contribute in solving this, feel free to!

 

Tested with all 3 options, builds and runs smoothly.

 

My recommendation: Test and make LEGDEPS the new default, getting rid of all legacy folders. This is just my personal opinion as I like to work with latest technologies, nothing is gonna happen if we keep legacy as well (except not making the repo lighter).

 

Share your thoughts below and if you want to make an improvement or contribute in any way I would be very happy for it 🙂

 

Test before PR is merged:

Server:

git clone --recursive --branch exp_2/src-improvs-and-submodules --single-branch https://github.com/MindRapist/m2dev-server-src.git

Client:

git clone --recursive --branch exp_3/src-improvs-and-submodules --single-branch https://github.com/MindRapist/m2dev-client-src.git

 

Edited by Mind Rapist
  • Love 2
On 12/5/2025 at 12:58 AM, DasSchwarzeTv2 said:

That means everybody is still developing in VMs? Cannot imagine that tbh

No I have BSD installed like a primary OS on my pc..

On 10/13/2025 at 9:23 PM, tw1x1 said:

Someone just shared the fix above, just read the topic carefully. Check here

same problem

  • Active+ Member

The messenger window and functionalities are completely unbugged and will be included in the next major PR update!

What to expect:

  • P2P Cross channel/core requests (by @ Amun)
  • The messenger auto-updates on both parties in both adding and removing a friend (same core + cross-core)
  • The messenger initializes on game phase (without opening of course) so that it receives updates normally.
  • The friend request is automatically denied on escape key press of the dialog (you'll see why that's important below)
  • All previous unanswered requests towards the companion are deleted upon new request.
  • New chat packets and returns for messenger_manager for request overflow prevention towards late adding/accepting functions of the server and towards the companion:
    • You cannot add your self as a friend (this was already here but had no message)
    • %s has already sent you a friend request.
    • You have already sent a friend request to %s.
    • You and %s are already friends.
  • Automatic deletion of all unanswered incoming and outcoming requests from/to the character when they logout, teleport, get kicked, any type of disconnection. This is very important so that they can interact again with the same person again after a logout in case I missed something.
  • All chat packet messages and functionalities (including quest::CQuestManager::instance().GetPCForce(target->GetPlayerID())->IsRunning() and target->IsBlockMode(BLOCK_MESSENGER_INVITE) work cross-core/channel via a GG packet header, as well as same-core the way it already works.
  • The messenger window auto-disables the Whisper and Remove button when the selected friend is removed/removes the character from their own window, in both parties
  • No more name overlapping after a deletion. Tested with the Friends section expanded and collapsed.
  • The "Friend" button auto updates in both parties after both adding and removing a friend in the target board of the character.

Tested thouroughly and works! Still, feel free to test it, restructure the code, TEST IT AGAIN and of course provide feedback.

Edited by Mind Rapist
  • Love 3
  • Active+ Member

UPDATE:

All compiler warnings for FreeBSD builds fixed (not silenced) for common, db, game, liblua, libthecore, qc projects (the rest didn't have any). Available in the next major PR.

 

BUG/QUESTION:

Does anyone else have this:

Login with 3 characters and have them meet in the same map. The last one (viewer) must teleport there while the other 2 are there already, don't move them until the third one arrives. Engage the other 2 in PVP. In each window, only the main character moves and hits, the other 2 don't update. Happens in all 3 window (only the main window's character is moving and hitting). Do you guys have this and if yes do you have any idea where to look for the fix?

  • Love 1
1 hour ago, Mind Rapist said:

UPDATE:

All compiler warnings for FreeBSD builds fixed (not silenced) for common, db, game, liblua, libthecore, qc projects (the rest didn't have any). Available in the next major PR.

 

BUG/QUESTION:

Does anyone else have this:

Login with 3 characters and have them meet in the same map. The last one (viewer) must teleport there while the other 2 are there already, don't move them until the third one arrives. Engage the other 2 in PVP. In each window, only the main character moves and hits, the other 2 don't update. Happens in all 3 window (only the main window's character is moving and hitting). Do you guys have this and if yes do you have any idea where to look for the fix?

Every source has this, that’s a desync situation

  • Love 2
  • Active+ Member
8 minutes ago, tw1x1 said:

Every source has this, that’s a desync situation

Trust me not in this level. I had a message from another person with the same issue different cause. I've seen this "issue" in it's "default-mode" but what I noticed was nothing compared to that. I could be wrong though I'm not very experienced, just seemed nothing like I've seen so far. Is it normal that a die & revive fixes the issue for the revived character?

After countless hours fighting the bugs (and countless yet to come), me and @tw1x1 decided to share with you our trello board link so you can track our progress, plans, as well as make suggestions about the future shape of this amazing project.

I am aware that there is an official trello board about this but since it's been inactive for a little while now and we cannot manage it we created this one.

https://trello.com/invite/b/692df71ec1378eda7dc0a883/ATTI2ade746ee27d63b72a1fe2ef921f1383AA53CA7C/m2dev-project

Let us know what you think!

  • Honorable Member
On 12/6/2025 at 6:11 PM, Mind Rapist said:

New PR requests submitted

These PR requests include client and server sources and they are re-constructing the way that CMake configuration works.

 

Introducing Git Submodules:

Git submodules are "repos within repos". The new system uses a Python script upon running

cmake -S . -B build

to automatically download all vendors and includes from their respective Github repos, place each file in the correct folder, delete the downloaded repos that are not required to exist as a repo (for example only the 2 header files from STB Image are copied into include folder, the rest of the downloaded repo is discarded)

Disabled by default, MUST BE ENABLED

 

New structure for include, extern/include and vendor folders in both projects (example):

Was: /vendor/spdlog-1.15.7

New: /vendor/legacy/spdlog-1.15.7, /vendor/latest/spdlog

 

Client source:

The following includes are NOT being updated by the script and remain in include/common:

  • SpeedTreeRT
  • DirectX 9 EX (and relevant headers)
  • Python
  • Anything that is close-sourced or cannot be implemented in the latest version

 

How to choose:

I know that most people don't like change, new versions, familiar feels safer, or simply don't want to bother testing and getting involved with updated libs.

Nothing is changed by default. By running:
 

cmake -S . -B build

everything remains as you know it, with the vendors and includes you've been using so far.

In order to use the latest versions, simply:
 

cmake -S . -B build -DUSE_LEGDEPS=OFF

for a one-time off, or set this option to ON in the root CMakeLists.txt, so you won't have to include it every time in the CMake command.

 

Can I rollback to a custom version of a dependency?

YES! By setting the submodule's versio, adding and committing (locally), your configuration uses now the selected version. You must manually specified the latest (or another) version to abort this. Commands (with Crypto++ as an example):

 > git -C vendor/latest/cryptopp checkout v8.6.0
 > git add vendor/latest/cryptopp
 > git commit -m "Upgrade Cryptopp to v8.6.0 just because I can!"
 > cmake -S . -B build

 

Tested with both options, builds and runs smoothly.

 

Server source:

All includes and vendors are updatable!

How to choose:

I know that most people don't like change, new versions, familiar feels safer, or simply don't want to bother testing and getting involved with updated libs.

Nothing is changed by default. By running:
 

cmake -S . -B build

everything remains as you know it, with the vendors and includes you've been using so far.

In order to use the latest versions, simply:
 

cmake -S . -B build -DUSE_LEGDEPS=OFF

for a one-time off, or set this option to ON in the root CMakeLists.txt, so you won't have to include it every time in the CMake command.

 

 

 HIGHLY EXPERIMENTAL!

[NEW] SIL (System Installed Libaries - FreeBSD ONLY!)

With SIL=ON you

  • Ensure latest version dependencies (like with LEGDEPS=OFF)
  • Source builds FASTER!
    • Spdlog:                                  -1% of the build
    • MariaDB Connector C :        -18% of the build
    • Crypto++ (coming soon):    -30% of the build

Use cmake -S . -B build -DUSE_SIL=ON to completely ignore includes and vendors in the project's directory and instead use:

  • /usr/local/include</XX> for Includes
  • /usr/local/lib for libraries

Requirement: included ports must be installed in order to use this

Verify if a port is installed with

#pkg info <port>
 > pkg info spdlog

If no information about your selected port are shown, install it (port method is highly recommended)

# Find it first
 > whereis spdlog
 > cd /usr/ports/devel/spdlog
 > make install clean

Find all required ports in the root CMakeLists.txt

 

When SIL is ON, LEGDEPS=ON is automatically ignored, ensuring the latest versions are used, READ MORE BELOW 👇👇👇

⚠️ Caveats:

  • Crypto++ is EXCLUDED from SIL. Why??? Crypto++ version > 8.7.0 is incompatible when not built with CMake. When SIL is ON, CMake is being built from vendor/latest/cryptopp as usual. Attempts to include /usr/local/lib/libcryptopp.a caused auth channel crashes, Handshake process infinite loops, client login screen getting stuck to "Connecting to server..." message.
    If you have some experience and wanna contribute in solving this, feel free to!

 

Tested with all 3 options, builds and runs smoothly.

 

My recommendation: Test and make LEGDEPS the new default, getting rid of all legacy folders. This is just my personal opinion as I like to work with latest technologies, nothing is gonna happen if we keep legacy as well (except not making the repo lighter).

 

Share your thoughts below and if you want to make an improvement or contribute in any way I would be very happy for it 🙂

 

Test before PR is merged:

Server:

git clone --recursive --branch exp_2/src-improvs-and-submodules --single-branch https://github.com/MindRapist/m2dev-server-src.git

Client:

git clone --recursive --branch exp_3/src-improvs-and-submodules --single-branch https://github.com/MindRapist/m2dev-client-src.git

 

Sorry, but I'll have to discard this PR. I deliberately did not use submodules, vcpkg and other things so the repo is completely self contained and not dependent on the availability of other repositories or pre-installed system libraries.

This would break this principle.

What if a repository gets deleted or made private?
For pre-installed system libs it's even worse: what if there is a breaking change between the version we used and the version installed on the system? For example MariaDB is built with DEFAULT_SSL_VERIFY_SERVER_CERT=ON by default since version 3.4.

Maintainability and being able to reproduce the exact same builds are much more important than having lower build time in general.
Let's try to keep ourselves to standards.

 

3 hours ago, Mind Rapist said:

Trust me not in this level. I had a message from another person with the same issue different cause. I've seen this "issue" in it's "default-mode" but what I noticed was nothing compared to that. I could be wrong though I'm not very experienced, just seemed nothing like I've seen so far. Is it normal that a die & revive fixes the issue for the revived character?

After countless hours fighting the bugs (and countless yet to come), me and @tw1x1 decided to share with you our trello board link so you can track our progress, plans, as well as make suggestions about the future shape of this amazing project.

I am aware that there is an official trello board about this but since it's been inactive for a little while now and we cannot manage it we created this one.

https://trello.com/invite/b/692df71ec1378eda7dc0a883/ATTI2ade746ee27d63b72a1fe2ef921f1383AA53CA7C/m2dev-project

Let us know what you think!

Request access to the official Trello board so everything is kept together.

Edited by Distraught
  • muscle 1
  • Love 1

992404397646696589.png
Former C++ Developer at Gameloft on DML
Join my Discord: Distraught Labs

5 hours ago, Distraught said:

Sorry, but I'll have to discard this PR. I deliberately did not use submodules, vcpkg and other things so the repo is completely self contained and not dependent on the availability of other repositories or pre-installed system libraries.

This would break this principle.

What if a repository gets deleted or made private?
For pre-installed system libs it's even worse: what if there is a breaking change between the version we used and the version installed on the system? For example MariaDB is built with DEFAULT_SSL_VERIFY_SERVER_CERT=ON by default since version 3.4.

Maintainability and being able to reproduce the exact same builds are much more important than having lower build time in general.
Let's try to keep ourselves to standards.

 

Request access to the official Trello board so everything is kept together.

Can you share link please? I didn’t know about the official Trello board, that’s why i’ve created another one.

 

Thank you!

Edited by tw1x1
  • Active Member

Hey 😃
I have created my first PR for this project ❤️

This is the hidden content, please

I work on ubuntu so i made some changes in the server-src so you can compile it on ubuntu too.

  • Metin2 Dev 21
  • Good 2
  • Love 9
  • Active+ Member
10 hours ago, Distraught said:

Sorry, but I'll have to discard this PR. I deliberately did not use submodules, vcpkg and other things so the repo is completely self contained and not dependent on the availability of other repositories or pre-installed system libraries.

This would break this principle.

What if a repository gets deleted or made private?
For pre-installed system libs it's even worse: what if there is a breaking change between the version we used and the version installed on the system? For example MariaDB is built with DEFAULT_SSL_VERIFY_SERVER_CERT=ON by default since version 3.4.

Maintainability and being able to reproduce the exact same builds are much more important than having lower build time in general.
Let's try to keep ourselves to standards.

 

Request access to the official Trello board so everything is kept together.

Makes a valid point about the new CMake capabilities which is why I only added support for Git submodules and SIL, by default no change is required to obtain the changes + have everything working as they do now with the pre-installed versions so by a simple pull nothing changes.

My thoughts about this were:

  • LEGDEPS: turn them on to test out the latest version of a dependencie(s). If we like it we can keep it as the new standard version.
    It also supports adding custom versions, not necessarily the latest (specify by command one-time, or edit the .gitmodules file).
    Basically you can still control vendors and includes the same way by only pushing the versions you want in the official repo within the .gitmodules file, safely deleting all the folders and files that are not needed and therefore making the repo even lighter. And for whoever wants to work with other versions of vendors and includes despite the ones you specified, a simple command or a file edit is a little easier and faster than selecting individual files or entire repos to paste over the old ones.
    ON by default, must be turned OFF to fetch submodules
  • SIL: for those who have tested the latest version and nothing changes in code performance and simply want a faster build. It's been added as a new every-day method of building, after thourough testing of the targeted lib version.
    The list is extremely easy to modify to select only the libs you know they work.
    Some people will say that this is the only way they build their projects (each one for their own reasons) and the existence of this option would make the project building experience more familiar and convenient to them.
    OFF by default, must be turned ON to use system libs and includes

So eventually nothing changes, but from a single option we now have 3 with this new feature.

If you still wanna keep things as they are without the 2 extra options please let me know so I can exlcude this change from my next PR.

If you choose to go with this remember to discard any changes to the root CMakeLists.txt or check if the default values of the new options have been modified before merging.

If you choose not to go with this please let me know if you would approve the updated versions in my next PR:

  • Crypto++ 8.9.0
  • MariaDB Connector C: 3.4.8
  • spdlog: 1.16.0
  • ZSTD: 1.15.7
  • STB Image: 0.6.10
  • PCG-CPP: 0.9
  • Rapid JSON: 1.1.0
  • Microsoft WIL: 1.0.250325.1
  • Miniaudio: 0.11.23
  • Argparse: 3.2
  • LZO: 2.10
  • DirectXMath: apr2025
  • Mio: unknown/latest stable

Tested these versions and so far the projects build successfully and didn't notice any issues anywhere.

 

So in my next PR would you prefer me to include the 2 additional options, not include them but update the libs and includes, or discard everything about this feature?

 

Also I couldn't find access request in your trello board (can we somehow merge the 2 into 1? 🤔)

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.