Jump to content

Sonitex

Premium
  • Posts

    521
  • Joined

  • Days Won

    12
  • Feedback

    100%

Posts posted by Sonitex

  1. Actually, CInstanceBase holds the VID value and that one is set on the server once the entity is spawned. Essentially, CActorInstance is a big mess of components grouped into one class, so it only holds "resource variables" eg. motions, while the CInstanceBase holds the gameplay variables like name, level, etc. The concept is old and very far from the modern implementations of entities but hopefully, you'll understand.

    Correct, CPythonCharacterManager is responsible for the entities.

    • Love 1
  2. Loooooooooong story short:

    PythonPlayer is like a manager class responsible for your character's data. It is used on the Python side to get the data and display it later on and that's about it.

    CInstanceBase is like a wrapper for the entity class CActorInstance which holds all the needed components like animations, effects, collisions, etc.

  3. The difference between clang++ and clang++-devel lies in the version of the Clang compiler being used. Both are C++ compilers provided by the Clang project, but clang++-devel typically refers to the development version or a specific version of the Clang compiler. The specific differences between the two can vary depending on the context and the versions installed on your system.

    Regarding your side question, if thelibcore is strictly a C program, it is generally more appropriate to use a C compiler such as clang or gcc rather than a C++ compiler like clang++. Using a C++ compiler for a C program can lead to syntax errors or unexpected behavior, as C++ and C have slight differences in syntax and language features. Make sure that your Makefile is set up to use a C compiler (e.g., CC = clang or CC = gcc) instead of a C++ compiler.

    If you are encountering syntax errors or missing brackets when switching to a C compiler, it could be due to subtle differences between the C and C++ languages. Make sure that your code follows the C syntax and conventions and does not rely on C++-specific features. Additionally, ensure that your Makefile and build system are correctly configured to use a C compiler and include the necessary header files and libraries for C code.

     

    This was totally not generated by GPT.

  4. 28 minutes ago, Denizeri24 said:
    bool CClientManager::InitializeItemTable()
    {
    	std::map<int32_t, const char *> localMap;
    	cCsvTable nameData;
    
    	if (!nameData.Load("item_names.txt", '\t'))
    	{
    		fmt::fprintf(stderr, "item_names.txt couldn't be loaded or its format is incorrect.\n");
    		return false; // There's no reason to continue without names for us (i dont like korean)
    	}
    
    	nameData.Next(); // skip the description
    
    	while (nameData.Next())
    	{
    		localMap[static_cast<int32_t>(std::strtol(nameData.AsStringByIndex(0), nullptr, 0))] = nameData.AsStringByIndex(1);
    	}
    
    	cCsvTable data;
    
    	if (!data.Load("item_proto.txt", '\t'))
    	{
    		fmt::fprintf(stderr, "item_proto.txt couldn't be loaded or the format is incorrect \n");
    		return false;
    	}
    
    	data.Next(); // skip first row (descriptions)
    	m_vec_itemTable.resize(data.m_File.GetRowCount() - 1); // set the size of the vector
    	memset(&m_vec_itemTable[0], 0, sizeof(TItemTable) * m_vec_itemTable.size()); // zero initialize
    	auto item_table = &m_vec_itemTable[0];
    
    	for (; data.Next(); ++item_table)
    	{
    		if (!Set_Proto_Item_Table(item_table, data, localMap))
    		{
    			fmt::fprintf(stderr, "Invalid item table. VNUM: %u\n", item_table->dwVnum);
    		}
    
    		m_map_itemTableByVnum.emplace(item_table->dwVnum, item_table);
    	}
    
    	std::sort(std::execution::par, m_vec_itemTable.begin(), m_vec_itemTable.end(), FCompareVnum());
    	data.Destroy();
    	nameData.Destroy();
    	return true;
    }

    There's zero initialization here. So I don't think your fix is needed..

    Yep, you're correct, the issue is only present on default metin2 sources.

  5. Ayo,

    recently I've come across an issue with a customer who had item proto entries all over the place and when the database tried to sort that mess, it messed it up even more, eventually, it messed up this very Monday for me as I spent hours debugging this.

    Long story short: It first inserts key-value to map m_map_itemTableByVnum where the key was an integer (item vnum) and the value was a pointer that pointed to an item table object at position X in m_vec_itemTable but at the end, it sorted this very vector while values in map still pointed to the same positions in the vector. Guessed what happened? An item with vnum 19709 had an item table of the item with vnum 20009 because you donkey were too lazy to put new proto entries in the correct order. 

    Go over to server source, database/ClientManagerBoot.cpp, at the end of the following function:

    bool CClientManager::InitializeItemTable()
    {
    	[...]
    	m_map_itemTableByVnum.clear();
    
    	auto it = m_vec_itemTable.begin();
    
    	while (it != m_vec_itemTable.end())
    	{
    		TItemTable * item_table = &(*(it++));
    
    		sys_log(1, "ITEM: #%-5lu %-24s %-24s VAL: %ld %ld %ld %ld %ld %ld WEAR %lu ANTI %lu IMMUNE %lu REFINE %lu REFINE_SET %u MAGIC_PCT %u", 
    				item_table->dwVnum,
    				item_table->szName,
    				item_table->szLocaleName,
    				item_table->alValues[0],
    				item_table->alValues[1],
    				item_table->alValues[2],
    				item_table->alValues[3],
    				item_table->alValues[4],
    				item_table->alValues[5],
    				item_table->dwWearFlags,
    				item_table->dwAntiFlags,
    				item_table->dwImmuneFlag,
    				item_table->dwRefinedVnum,
    				item_table->wRefineSet,
    				item_table->bAlterToMagicItemPct);
    
    		m_map_itemTableByVnum.insert(std::map<DWORD, TItemTable *>::value_type(item_table->dwVnum, item_table));
    	}
    	sort(m_vec_itemTable.begin(), m_vec_itemTable.end(), FCompareVnum());
    	return true;

    Now we'll do some dark magic, we'll move the sort function at the beginning of previously shown code, like so:

    bool CClientManager::InitializeItemTable()
    {
    	[...]
    	m_map_itemTableByVnum.clear();
    
      	// -------------------------------------------------------------> Wohoo I am here now!
      	sort(m_vec_itemTable.begin(), m_vec_itemTable.end(), FCompareVnum());
    	auto it = m_vec_itemTable.begin();
    
    	while (it != m_vec_itemTable.end())
    	{
    		TItemTable * item_table = &(*(it++));
    
    		sys_log(1, "ITEM: #%-5lu %-24s %-24s VAL: %ld %ld %ld %ld %ld %ld WEAR %lu ANTI %lu IMMUNE %lu REFINE %lu REFINE_SET %u MAGIC_PCT %u", 
    				item_table->dwVnum,
    				item_table->szName,
    				item_table->szLocaleName,
    				item_table->alValues[0],
    				item_table->alValues[1],
    				item_table->alValues[2],
    				item_table->alValues[3],
    				item_table->alValues[4],
    				item_table->alValues[5],
    				item_table->dwWearFlags,
    				item_table->dwAntiFlags,
    				item_table->dwImmuneFlag,
    				item_table->dwRefinedVnum,
    				item_table->wRefineSet,
    				item_table->bAlterToMagicItemPct);
    
    		m_map_itemTableByVnum.insert(std::map<DWORD, TItemTable *>::value_type(item_table->dwVnum, item_table));
    	}
    	return true;

     

    • Good 2
    • Love 2
  6. 49 minutes ago, RnYPT said:

    I have a question regarding the windows server. Is there any disavantage in using this windows method instead of actual freebsd?

     

    Windows server is used explicitly for development as you can hook the running cores to Visual Studio and debug your life-mistakes easier and once you think you solved them, you ship it on FreeBSD in continue the misery there with GDB 🥲

    • Sad 1
  7. 11 minutes ago, TMP4 said:

    Sharing a buyer experience even if it's bad should be okey to do so. That's not the problem here.

    You said "Maybe I will be able to fix it sooner"
    He said yo said "maybe I'll fix it."

    That's the problem because the latter have different meaning. If you would say that, I would be angry too, but you said different thing.

    I didn't take the negative experience to heart but it was more about sharing private conversations online and interpreting my words in a wrong way.

  8. 4 minutes ago, drgdec said:

    spacer.png

     

    spacer.png

     

    spacer.png

     

    It doesn't seem right to me when you say "maybe I'll fix it."

     

    It was more about me not being able to provide support at that exact time as I was bombarded with exams so the only alternative was to disable it until I am available again. I was also completely transparent about this issue with a dozen of other potential customers and stopped the sales until it was resolved so I don't get this public "shaming" but you do you my friend :))

  9. Dynamic packet's size depends on the buffer's size that you're writing to. In your case you have set dynamic packet's size to X value, but you only wrote Y amount of data to the buffer and sent it to the client.

    Likely scenario is you are not increasing the packet's size concurrently with writing data to the buffer, but you're predefining it with some deprecated value e.g., old slot count or using wrong datatypes when determining the size.

  10. On 10/13/2022 at 7:50 PM, raihan3 said:

    how can i put locale_string without index like :
     

    
    "%sÀÌ ÇÊ¿äÇÕ´Ï´Ù.";
    "%s needed.";

    not 

    1	%s needed.

    i mean without DWORD dwIndex

    As stated in the first post you need to send the string index to the client but how you achieve that is up to you. You can create a new table of string-index and find the index there.

    This was more of a test and not really an end product therefore it is missing some features, also it was based on the C functions where now we have many other tools that would ease the process of fetching variadic arguments. 
     

  11. 22 minutes ago, ReFresh said:

    Thanks, but I'm not sure, if the bool should be there twice, but in another class. Is that correct?

     

    Hidden Content

     

    	protected:
    		friend class CInputDB;
    		bool		OnAfterCreatedItem();
    
    		//FIX REAL TIME FIRST USE
    		friend class CHARACTER;
    		bool		OnAfterCreatedItem();
    		//FIX REAL TIME FIRST USE

    Ah, as I can see, the way above will cause error with overloaded variable.

    So, this way is correct?

    	protected:
    		friend class CInputDB;
    
    		//FIX REAL TIME FIRST USE
    		friend class CHARACTER;
    		bool		OnAfterCreatedItem();
    		//FIX REAL TIME FIRST USE

    But then I can remove the friend class CInputDB; or not? It will be used in both classes at the same time? Yeah, maybe dumb question, but for me it's not really clear from your tut.

     

     

    That is correct but do not remove the other friend class as it is used for the same purpose just at a different item loading phase.

    Usually, I use [...] to indicate before/after code.

    • Metin2 Dev 1
  12. Yo!

    If you have an item with a limit type LIMIT_REAL_TIME_START_FIRST_USE that has been used at one point and put it inside the safe-box, it will not be removed from the game until you pull it out of the safe-box and perform a teleport.

    item.h

    // Search:
    	protected:
    		friend class CInputDB;
    
    
    // Add below:
    		friend class CHARACTER;

    char.cpp

    // Search:
    void CHARACTER::LoadSafebox(int iSize, DWORD dwGold, int iItemCount, TPlayerItem * pItems)
    {
    	[...]
    
    			if (!m_pkSafebox->Add(pItems->pos, item))
    			{
    				M2_DESTROY_ITEM(item);
    			}
    			else
    				item->SetSkipSave(false);
    
    // Modify to:
    			if (!m_pkSafebox->Add(pItems->pos, item))
    			{
    				M2_DESTROY_ITEM(item);
    			}
    			else
    			{
    				item->OnAfterCreatedItem();
    				item->SetSkipSave(false);
    			}

     

    • Metin2 Dev 8
    • Good 2
    • Love 1
    • Love 8
  13. 4 minutes ago, LMAOAtWannabeDevs said:

     

    I didn't even look at the source files but if you read the ingame description for double drop on equippable items it says it gives a chance to drop 2 items, instead of 1.

    OBVIOUSLY this means somewhere there is a seperate calculation for the chance to drop a second item after one has already been determined to be dropped.

    The only thing that's a lie here is the myth of Pserver devs being competent at all 🙂

    I'd love to see that separate item drop calculation of yours 🤡

    • Love 1
    • Love 1
  14. Spoiler

    062105banner.png

    Dear wild Metin2 enthusiasts,

    We are searching for a freelancer in the graphic design domain. More specifically, someone who will refashion the nostalgia present in Metin2's user-interface. The requirements are as follows:

    •    good understanding of graphic design principles
    •    ability to draw on tablet (recommended) 
    •    UI elements animating skills
    •    able to speak and write fluent English 
    •    commitment to the project

    Your job would be to modify an existing UI in PSD format and later on create new user interface windows upon it. Another task would be animating certain UI elements such as buttons eg. a hover effect and other simple decorative animations.

    Detailed instructions would be given to you for any kind of modification or request. It is also possible (recommended) to discuss ideas and wishes via a voice call.

    If you think you are up for a challenge, I invite you to a chat over Discord (Sonitex#1880).

    Kind Regards,

    Sonitex

  15. 1 minute ago, DrTurk said:

    ye better, the thing that i did was without checking if the string is empty

    Oh, I didn't see that you edited the post 🤣 

    Better be safe in case the client cannot find the requested string and appends empty space in chat window. 

    Thank you for sharing the notice function with others 🙂 

     

  16. We can just use the default setup that is used in normal chat packet for displaying notices.

     

    UserInterface/PythonNetworkStreamPhaseGame.cpp - CPythonNetworkStream::RecvLocaleChatPacket()

    // Search:
    		if(!localeString.empty())
    			CPythonChat::Instance().AppendChat(kChat.type, localeString.c_str());
    
    // Replace:
    		if(localeString.empty())
    			return true;
    
    		if (CHAT_TYPE_NOTICE == kChat.type)
    		{
    			PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_SetTipMessage", Py_BuildValue("(s)", localeString.c_str()));
    		}
    		else if (CHAT_TYPE_BIG_NOTICE == kChat.type)
    		{
    			PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_SetBigMessage", Py_BuildValue("(s)", localeString.c_str()));
    		}
    		else
    			CPythonChat::Instance().AppendChat(kChat.type, localeString.c_str());
    • Good 2
×
×
  • 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.