Jump to content

Distraught

Honorable Member
  • Posts

    194
  • Joined

  • Last visited

  • Days Won

    23
  • Feedback

    0%

Posts posted by Distraught

  1. 12 hours ago, Mutulic said:

    Gameforge coming too :))

    Educational purpose: Using a work for educational purposes weighs in favor of fair use.

  2. Hi all,

    Yesterday, we brainstormed the concept of hosting a real-life M2Dev conference, akin to a game development day, featuring prominent figures from our community delivering TED-style talks on a variety of subjects.

    As of now, the idea has backing from @ Apranax@ masodikbela@ Zerial@ .plechito'@ Deliris@ VegaS™ and myself, all of whom are committed to speaking at the event. We're targeting this fall, around October or November, in Budapest for the event.

    To gauge interest, I'm putting up a poll. If there's sufficient enthusiasm, we'll kick off the planning process.

    • Metin2 Dev 5
    • Eyes 1
    • Not Good 1
    • Think 1
    • Scream 1
    • Good 5
    • muscle 2
    • Love 11
  3. This is the hidden content, please

     

    Hello everyone,

    Some time ago I created this memory leak finder for Land of Heroes, but we don't really use it anymore so I decided to release it.

    You can use it only on Windows (otherwise you have to modify it a bit), and you will need

    This is the hidden content, please
    for it to work.

    namespace MemoryLeakFinder
    {
    	typedef void* (__cdecl* _malloc)(_In_ _CRT_GUARDOVERFLOW size_t _Size);
    	typedef void (__cdecl* _free)(_Pre_maybenull_ _Post_invalid_ void* _Block);
    
    	_malloc True_malloc = (_malloc) ::malloc;
    	_free True_free = (_free) ::free;
    
    	template <class T>
    	class NoTraceAllocator
    	{
    	public:
    		using value_type = T;
    		NoTraceAllocator() noexcept {}
    		template <class U> NoTraceAllocator(NoTraceAllocator<U> const&) noexcept {}
    		value_type* allocate(std::size_t n)
    		{
    			return static_cast<value_type*>(True_malloc(n * sizeof(value_type)));
    		}
    		void deallocate(value_type* p, std::size_t) noexcept
    		{
    			True_free(p);
    		}
    	};
    
    	static bool GetStackWalk(char* outWalk)
    	{
    		::SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_UNDNAME);
    		if (!::SymInitialize(::GetCurrentProcess(), "http://msdl.microsoft.com/download/symbols", TRUE))
    			return false;
    		PVOID addrs[25] = { 0 };
    		USHORT frames = CaptureStackBackTrace(1, 25, addrs, NULL);
    
    		char* ptr = outWalk;
    		for (USHORT i = 0; i < frames; i++)
    		{
    			ULONG64 buffer[(sizeof(SYMBOL_INFO) + 1024 + sizeof(ULONG64) - 1) / sizeof(ULONG64)] = { 0 };
    			SYMBOL_INFO* info = (SYMBOL_INFO*)buffer;
    			info->SizeOfStruct = sizeof(SYMBOL_INFO);
    			info->MaxNameLen = 1024;
    			DWORD64 displacement = 0;
    			if (::SymFromAddr(::GetCurrentProcess(), (DWORD64)addrs[i], &displacement, info)) 
    			{
    				ptr += sprintf_s(outWalk, 1024, "%s\n", info->Name);
    			}
    		}
    		::SymCleanup(::GetCurrentProcess());
    		return true;
    	}
    
    	std::unordered_map<void*, const char*
    		, std::hash<void*>
    		, std::equal_to<void*>
    		, NoTraceAllocator<std::pair<const void*, const char*>>> memoryAllocations;
    
    	void* My_malloc(_In_ _CRT_GUARDOVERFLOW size_t _Size)
    	{
    		void* ptr = True_malloc(_Size);
    		char* stackTrace = (char*)True_malloc(1024);
    		GetStackWalk(stackTrace);
    		memoryAllocations.emplace(std::make_pair(ptr, stackTrace));
    		return ptr;
    	}
    	void My_free(_Pre_maybenull_ _Post_invalid_ void* _Block)
    	{
    		auto it = memoryAllocations.find(_Block);
    		if (it != memoryAllocations.end())
    		{
    			True_free((void*)it->second);
    			memoryAllocations.erase(it);
    		}
    		return True_free(_Block);
    	}
    
    	void StartMemoryLeakFinder()
    	{
    		Mhook_SetHook((PVOID*)&True_malloc,
    			My_malloc);
    		Mhook_SetHook((PVOID*)&True_free,
    			My_free);
    	}
    
    	void StopMemoryLeakFinder()
    	{
    		Mhook_Unhook((PVOID*)&True_malloc);
    		Mhook_Unhook((PVOID*)&True_free);
    
    		std::ofstream ofs("memoryleaks.txt");
    		for (auto it = memoryAllocations.begin(); it != memoryAllocations.end(); ++it)
    		{
    			ofs << it->second << std::endl;
    			True_free((void*)it->second);
    		}
    		ofs.close();
    	}
    }

     

    You have to call StartMemoryLeakFinder() and StopMemoryLeakFinder() where you'd like them to start and stop accordingly.

    • Metin2 Dev 159
    • Eyes 2
    • Scream 1
    • Good 35
    • Love 3
    • Love 56
  4. You just need to modify the return value of CArea::GetMaxLoadingDistanceSqr function, that's why I put this into a seperated function so it's easy to implement a slider.

    For example interpolate between pfStart and pfFarClip. Just add a new option to CPythonSystem and a slider in python which sets its value and you can use the value of the sliderbar as it is (0.0-1.0).

    float CArea::GetMaxLoadingDistanceSqr() const
    {
    	int peNum;
    	float pfStart, pfEnd, pfFarClip;
    	CPythonBackground::instance().GetDistanceSetInfo(&peNum, &pfStart, &pfEnd, &pfFarClip);
    
    	// you need to get your value for exmaple from CPythonSystem or from whenever you want
    	float fRatio = CPythonSystem::instance().GetLoadingDistance();
    
    	// use one of the interpolation functions i provided
    	return LinearInterpolation(pfStart * pfStart, pfFarClip * pfFarClip, fRatio);
    }

     

    • Love 3
  5. Hello guys,

    I didn't like the basic memory pooling solution in the client so I extended and rewrote some parts of it.

    • now it allocates memory in chunks instead of one by one, the chunk's size can grow
    • Alloc can have any parameters, so you don't need to use only default constructors
    • ctors and dtors are called properly for each object created by the pool and also on unfreed objects on Clear

    Keep in mind, that it's not a drop-in replacement for every case where the old one was used, you may need to modify your code at some places, so I suggest porting to this new version one by one.

    Good luck!

    template<typename T>
    class CMemoryPoolNew
    {
    public:
    	CMemoryPoolNew(size_t uChunkSize = 16, bool bGrowChunkSize = true)
    		: m_uChunkSize(uChunkSize)
    		, m_bGrowChunkSize(bGrowChunkSize)
    	{
    
    	}
    
    	~CMemoryPoolNew()
    	{
    		Clear();
    	}
    
    	void Clear()
    	{
    		assert(m_Free.size() == m_Data.size() && "Memory pool has unfreed objects!");
    
    		if (m_Free.size() != m_Data.size())
    		{
    			for (T* pData : m_Data)
    			{
    				if (std::find(m_Free.begin(), m_Free.end(), pData) == m_Free.end())
    				{
    					pData->~T();
    				}
    			}
    		}
    
    		m_Data.clear();
    		m_Data.shrink_to_fit();
    
    		m_Free.clear();
    		m_Free.shrink_to_fit();
    
    		for (T* pChunk : m_Chunk)
    		{
    			::free(pChunk);
    		}
    
    		m_Chunk.clear();
    		m_Chunk.shrink_to_fit();
    	}
    
    	template<class... _Types>
    	T* Alloc(_Types&&... _Args)
    	{
    		if (m_Free.empty())
    			Grow();
    
    		T* pNew = m_Free.back();
    		m_Free.pop_back();
    		return new(pNew) T(std::forward<_Types>(_Args)...);
    	}
    
    	void Free(T* pData)
    	{
    		pData->~T();
    		m_Free.push_back(pData);
    	}
    
    	size_t GetCapacity() const
    	{
    		return m_Data.size();
    	}
    
    private:
    	void Grow()
    	{
    		size_t uChunkSize = m_uChunkSize;
    
    		if (m_bGrowChunkSize)
    			uChunkSize += uChunkSize * m_Chunk.size();
    
    		T* pStart = (T*) ::malloc(uChunkSize * sizeof(T));
    		m_Chunk.push_back(pStart);
    
    		m_Data.reserve(m_Data.size() + uChunkSize);
    		m_Free.reserve(m_Free.size() + uChunkSize);
    
    		for (size_t i = 0; i < uChunkSize; ++i)
    		{
    			m_Data.push_back(pStart + i);
    			m_Free.push_back(pStart + i);
    		}
    	}
    
    private:
    	size_t m_uChunkSize;
    	bool m_bGrowChunkSize;
    
    	std::vector<T*> m_Data;
    	std::vector<T*> m_Free;
    
    	std::vector<T*> m_Chunk;
    };

     

    • Metin2 Dev 6
    • Good 3
    • Love 1
    • Love 9
  6. Thank you guys ❤️

      

    31 minutes ago, Ulthar said:

    Thanks! ^^
    Do we need to create the python part for ourselves? 😮

    @ ASIKOO #honorablefordistraught

    Yes, that's not included, it will use the clipping distance by default. You can play with the distance in CArea::GetMaxLoadingDistanceSqr.

  7. Hello everyone,

    I was optimizing the loading of maps for my server and I decided to share it with the public. With this modifications, only the objects and effects around the character will be loaded and it will handle their load and unload as you move around. Also effect updatings are optimized a way that closer effects are updated more frequently.

    .gif

    Okay, so let's start the work 😄

    This is the hidden content, please

     

    Good luck! 🙂

    • Metin2 Dev 253
    • Eyes 6
    • Dislove 2
    • Not Good 1
    • Sad 1
    • Cry 1
    • Scream 4
    • Good 45
    • Love 13
    • Love 98
  8. Hello guys,

    As we know, if you have a lot of images in an ani-image, it can be really slow to load and may makes the game freeze for a moment. It really limits us, because we can't use a longer image sequence as it would have a bad impact on user experience.

    I created a sequence of 126 images by concatenating some of our tutorials, so here's a comparison GIF that shows the old (left) and new (right) version.

    .gif

    The main problem is that it loads all the images in a loop when we initialize it.

    .png

    And they are loaded when we call AppendImage function.

    .png

     

    We can delay and separate the loading of images in the update cycle to different frames, so the game won't freeze because just one image per frame will be loaded instead of them all at once.

     

    How to do this? Step by step tutorial.

    This is the hidden content, please

     

    That's all, we're finished! 🙂

    Good luck!

    • Metin2 Dev 198
    • kekw 1
    • Eyes 1
    • Dislove 1
    • Angry 1
    • Cry 1
    • Think 4
    • Confused 1
    • Scream 1
    • Lmao 2
    • Good 30
    • Love 5
    • Love 47
  9. I think some of you faced this bug when you had a monster with more then 21 million HP: the gauge showed 0% even when it was on full HP.

    It's because when the server calculates the HP percentage is like MINMAX(0, (m_pkChrTarget->GetHP() * 100) / m_pkChrTarget->GetMaxHP(), 100), so 21 million will overflow when it's multiplied by 100.

    The fix is really quick and easy:

    This is the hidden content, please

    • Metin2 Dev 169
    • Eyes 2
    • Not Good 3
    • Good 39
    • Love 5
    • Love 52
  10. Land of Heroes is looking for a Polish translator.

    You'll have access to our localizations on our SVN server.

    They are in Excel files, so it's going to be really straight-forward how to translate them. You can translate from English, Hungarian, Romanian or Turkish either.

    zRhQUSG.png

    Payment method: Normal bank transfer, we do not use and don't intend to use PayPal.

     

    If you're interested, hite me up here or on Discord ( Erik Schvarcz#8481 )

  11. Make ProcessDamage return with a boolean value. Return false if the damage queue is empty and return true at other returns and at the end of the function.

    This is the hidden content, please

    And in CInstanceBase::Update put ProcessDamage in a loop like this.

    This is the hidden content, please

    • Metin2 Dev 155
    • Eyes 1
    • Dislove 1
    • Sad 1
    • Good 40
    • Love 3
    • Love 39
  12. 8 hours ago, Karbust said:

    I just made it like this, since it only throws the assert on DEBUG...

    std::shared_ptr<CGrannyMotion> CGraphicThing::GetMotionPointer(int iMotion)
    {
    #ifdef _DEBUG
    	if (!CheckMotionIndex(iMotion))
    		return NULL;
    #else
    	assert(CheckMotionIndex(iMotion));
    #endif
    
    	if (iMotion >= m_pgrnFileInfo->AnimationCount)
    		return NULL;
    
    	if (m_motions.empty())
    		return NULL;
    
    	return m_motions.at(iMotion);
    }

     

    Asserts are only compiled in debug builds anyway. Putting that extra check there only in debug mode and not even asserting is the worst case. It just hides errors during the development process but they can appear on live.

  13. Land of Heroes is looking for Game / Game Economy Designers

    What skills should a game designer have?
     • creativity
     • experience with a lot of games (mostly MMORPGs)
     • understanding different types of gamers, their needs and the way they work (Bartle taxonomy)
     • ability to think outside the box and then sync those ideas to fit in the game
     • minimal knowledge for Excel as we have all our data and game settings in xlsx files that game designers edit

    What skills should a game economy designer have?
     • good with numbers
     • ability to oversee the whole game's balances
     • experience at designing loot systems, designing the strength and settings of items and monsters, and forecasting the impact of new features on the game and its economy 
     • defining and maintaining the values of currencies (soft and hard) and preventing inflation
     • understanding F2P monetization, boosting ARPDAU

    This is a part time job and we provide weekly payments.

    You can apply at https://forms.gle/aC3Yrc4ntdgxHVUr5

  14. 8 hours ago, Tatsumaru said:

    Amazing how much you give to this community. More than one would cram their offers with what you share for free.

    Have you ever heard of voicechat? Maybe you could try to make such a system. This is just a suggestion.

     

    At Land of Heroes we have ingame voice-chat, but people rarely use it.

    • Metin2 Dev 1
×
×
  • 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.