Jump to content

Amun

Contributor
  • Posts

    199
  • Joined

  • Last visited

  • Days Won

    1
  • Feedback

    100%

Posts posted by Amun

  1. // char.h
    	void				ClearStone();
    
    // Replace with
    	void				ClearStone(LPCHARACTER pkKiller = nullptr);
    
    
    
    // char.cpp
    void CHARACTER::ClearStone()
    
    // Replace with this
    void CHARACTER::ClearStone(LPCHARACTER pkKiller)
    {
    	if (!m_set_pkChrSpawnedBy.empty())
    	{
    		// Kill all monsters I spawned.
    		FuncDeadSpawnedByStone f(pkKiller);
    		std::for_each(m_set_pkChrSpawnedBy.begin(), m_set_pkChrSpawnedBy.end(), f);
    		m_set_pkChrSpawnedBy.clear();
    	}
    
    	if (!m_pkChrStone)
    		return;
    
    	m_pkChrStone->m_set_pkChrSpawnedBy.erase(this);
    	m_pkChrStone = nullptr;
    }
    
    
    // Find this struct and replace it
    struct FuncDeadSpawnedByStone
    {
    private:
    	LPCHARACTER m_pkKiller;
    
    public:
    	FuncDeadSpawnedByStone(LPCHARACTER pkKiller) : m_pkKiller(pkKiller)
        {}
    
    	void operator () (LPCHARACTER ch)
    	{
    		ch->Dead(m_pkKiller);
    		ch->SetStone(nullptr);
    	}
    };
    
    
    // char_battle.cpp
    		if (IsStone())
    			ClearStone();
    
    // replace with
    		if (IsStone())
    			ClearStone(pkKiller);

     

    I didn't even try to compile it. Lemme know if it works

    • Love 2
  2. ResetFrame:
    This is used in the 2018 root to reset animations. It's already implemented in the source, but wasn't included in the module.

     

    If anyone needs it:

    PythonWindowManagerModule.cpp

    PyObject* wndMgrAniResetFrame(PyObject* poSelf, PyObject* poArgs)
    {
        UI::CWindow* pWindow;
        if (!PyTuple_GetWindow(poArgs, 0, &pWindow))
            return Py_BuildException();
    
        if (!pWindow)
            return Py_BuildException();
    
        ((UI::CAniImageBox*)pWindow)->ResetFrame();
    
        return Py_BuildNone();
    }
    
    { "ResetFrame",                    wndMgrAniResetFrame,                        METH_VARARGS },

    root, ui.py:

    # find
    class AniImageBox(Window):
    
    # find 
    	def SetEndFrameEvent
    
    # add
    	def ResetFrame(self):
    		wndMgr.ResetFrame(self.hWnd)

     

    • Love 1
  3. On 3/5/2023 at 9:40 AM, mageth said:

    0305 10:18:00550 :: Failed to load script file : new_login/LoginWindow.py
    0305 10:18:00551 :: 
    ui.py(line:2781) LoadScriptFile
    system.py(line:192) execfile
    system.py(line:163) Run
    new_login/LoginWindow.py(line:305) <module>

    LoadScriptFile!!!!!!!!!!!!!! - <type 'exceptions.AttributeError'>:'module' object has no attribute 'SALVEAZA_CONT'

    0305 10:18:00551 :: ============================================================================================================
    0305 10:18:00551 :: Abort!!!!


    0305 10:18:00553 :: 
    introLogin.py(line:223) __LoadScript
    ui.py(line:2798) LoadScriptFile
    exception.py(line:36) Abort

    LoginWindow.__LoadScript.LoadObject - <type 'exceptions.SystemExit'>:

    0305 10:18:00553 :: ============================================================================================================
    0305 10:18:00553 :: Abort!!!!

    I can't figure out what's wrong pls help

    https://docs.python.org/3/tutorial/modules.html

    https://bobbyhadz.com/blog/python-attributeerror-module-has-no-attribute

    https://www.google.com/search?q=python+module+has+no+attribute

  4. Spoiler

      

    16 minutes ago, xXIntelXx said:

     

    The problem is not the transition to be done instantly (it's irrelevant as long as the client is still processing in the background)

    This is what happens when moving with W (so W pressed and left click on the bar at the same time without releasing it):

    https://metin2.download/picture/577iCuT4g8a26z941R9dHO817H5tNf35/.gif

    This is what happens when moving just clicking left click once:

    https://metin2.download/picture/N4ZAQcgKtYRoABf9YdU43WgjBRK24RpY/.gif

     

    Side note when I was banging my head to the wall, I stumbled upon a post saying:"Your application is most likely "freezing" because it has a WinMain loop similar to this:

    while (true) 
    {
        if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
           TickGame();
        }
    }

    Guess what do we have here..

    void CPythonApplication::Loop()
    {    
        while (1)
        {    
            if (IsMessage())
            {
                if (!MessageProcess())
                    break;
            }
            else
            {
                if (!Process())
                    break;
    
                m_dwLastIdleTime=ELTimer_GetMSec();
            }
        }
    }

     

    bool CMSApplication::IsMessage()
    {
    	MSG msg;
    
    	if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
    		return false;
    
    	return true;
    }

     

    bool CMSApplication::MessageProcess()
    {
    	MSG msg;
    
    	if (!GetMessage(&msg, NULL, 0, 0))
    		return false;
    
    	TranslateMessage(&msg);
    	DispatchMessage(&msg);
    	return true;
    }

     

     

    Ah, yes, I see what you mean. It does, indeed, freeze when keeping the button pressed and then clicking the window.

     

    Also, yeah, I went through all of those forum topics/stackoverflow questions/docs.. It's been a while, but I remember there were many things to take into consideration when making the game loop.


    I will fix this(button thingy) as well at some point, but I can't promise anything because I won't have a lot of free time for the next month or so.

     

    • kekw 1
  5. 4 minutes ago, dumita123 said:

    What Intel was saying is that if you're holding the left/right click on the bar without moving the mouse at all, the game will still freeze for around 300-500ms.
    My post was only related to the context menu (because it was freezing the client while it was opened) so it just removes that option since no one was using it anyway.

    Ah, yes, I just noticed now. If you want the transition to be done instantly, keep the thread opened at all times and just let it know when it can and can't call Process, instead of triggering a new future whenever you click the bar. ez

  6. On 2/26/2023 at 10:08 AM, Dr3Ame3r said:

    Tested, it works, but, with a slight little problem, after the loading phase ends (the loadingscreen photos disappear) and it should popup your character, it freezes for about 0.7-1s until it shows entities near you(that happens only 1 time for each client)

    Yes, and I said that in the readme. If you want to avoid that, load npclist ahead of time and send the entities before the game world is shown. I didn't bother to make that as well because I wanted to keep it simple, so that everyone(or most people) can understand what's going on.

     

    If you consider that to be a big problem and have the knowledge to do what I said earlier, you can do it and post it here, so that everyone can use. Unfortunately, I'm extremely busy at the moment, so I won't be able to work on community stuff for a while.

     

    Cheers!

    - Amun

  7. 15 hours ago, xXIntelXx said:

    This still won't fix the problem when left clicking on the bar (and keeping the left click down, same with the right click). When moving, the player will keep moving in background and the window will also unfreeze, but not when auto attacking and pressing the spacebar, or moving pressing W (basically pressing any button while keeping the menubar clicked fucks it up. I still haven't found a solution for that but I also don't know if it causes to fly bug an enemy character).

    Actually, it does. I can use the keyboard normally(move, attack, write) while dragging/keeping the window(left click). I've not thought about fixing the right click as well(for some reason). Also, I was extremely busy, so I've not checked to see if Dumita's change will help in that regard.

     

    These being said, however, you can trigger/close the thread when entering and exiting the context menu. I don't see why you wouldn't be able to use the same solution for the right click as well.

     

    Edit: Just noticed(forgot about it) I also have a video of me moving when dragging the client:

     

    Regards,

    Amun

  8. Tested on x86 client/server. Fix for x64 server/x86 client coming soon.

    If I left something out, feel free to let me know and I'll update the tutorial.

     

    I only use Visual Studio/Windows - No tutorial for FreeBSD yet.

    I'll do it in the future, if no one comes further with it.

     

    Here it is:

    This is the hidden content, please
     or 
    This is the hidden content, please

    I uploaded the precompiled libs as well(for the lazy fucks who don't want to learn how to do it themselves).

     

    This will also fix your(invisible/white/broken) Guild Mark problem for whoever tried to update to 1.8 and didn't enable JPG support

     

    Good luck

     

    • Metin2 Dev 85
    • Eyes 2
    • Good 21
    • Love 2
    • Love 27
  9. 2 hours ago, hachiwari said:

    I dont know python, how will function 'move' behave with duplicates? (we know, sometimes ymir added corrected files wiht update)

    Don't know, I didn't think that far.

    I just made this shit for getting the entire pack ready for packing. I don't make granular updates, I'm just downloading the entire client, pack it, and bye(hence, the script).

     

    Feel free to test/extend it to your needs.

     

    Update: It'll replace the file with the new one.

    https://docs.python.org/3/library/shutil.html#shutil.move

     

    Update2: If you want granular updates, just add a function that recursively checks against your current pack folder using exists(path)

     

    Update3: Here, I've done it for you

    from os import listdir
    from os.path import exists, join, isdir
    
    #CONFIGS
    target_folder = "processed_from_raw_pack"
    pack_folder = "pack"#check against it recursively to see what's new in the target_folder
    
    f = open("diff.txt", "w")
    missing_files = ["MISSING_FILES\n"]
    can_add_section_separator = False
    
    def CheckAgainstOldPack(current_path = []):
        global can_add_section_separator
    
        for file in listdir(join(target_folder, *current_path)):
            current_path.append(file)
            _file_in_old_pack = join(pack_folder, *current_path)
    
            if isdir(_file_in_old_pack):
                CheckAgainstOldPack(current_path)
                current_path.pop(-1)
                continue
    
            if not exists(_file_in_old_pack):
                try:# Some files have fucked up names
                    print("MISSING ", _file_in_old_pack)
                    missing_files.append(_file_in_old_pack+"\n")
                    can_add_section_separator = True
                except:
                    pass
    
            current_path.pop(-1)
    
        if can_add_section_separator:#only add after each section of files, to simbolise different folders
            missing_files.append("\n")
            can_add_section_separator = False
    
    CheckAgainstOldPack()
    
    f.writelines(missing_files)
    f.close()

    Video:

     

    Edit it to remove the files if you need to. You can also timestamp the diffs and use them to reverse one of your updates as well(if needed), just read the list and remove the file, ez.

     

    • Good 1
  10. Good evening, fellow citizens of the forum,

     

    This is a script that automatically moves and creates folders for the official clients posted in "Official Unpacked Updates", getting them ready for packing.

     

     

    Video:

    Good luck,

    - Amun

     

    Update: Lol, I forgot to add the code xD

    Spoiler
    from os import listdir, mkdir
    from os.path import exists, join, isdir
    from shutil import move
    
    raw = "raw"
    target = "processed"
    
    def MoveFolders():
        if not exists(target):
            mkdir(target)
    
        for folder in listdir(raw):
            _from = join(raw, folder)
    
            if not isdir(_from) or folder == "root" or folder == "uiscript":
                print("Skipping {}".format(_from))
                continue
    
            if folder == "d_" or folder == "ymir work":
                MoveYmirFolders(folder)
                continue
    
            if folder == "locale" or folder == "locales":#Astro using locales
                MoveLocale(folder)
                continue
    
            _base = join(target, folder)
            _to = join(_base, folder)
    
            if not exists(_base):
                mkdir(_base)
    
            move(_from, _to)
            print("Moved folder {}".format(folder))
    
    
    def MoveYmirFolders(name):
        if name == "d_":
            ymir = join(raw, name, "ymir work")#astro
        else:
            ymir = join(raw, "ymir work")#p3ng3r
    
        for folder in listdir(ymir):
            _base = join(target, folder)
            if not exists(_base):
                mkdir(_base)
            
            _work = join(_base, "ymir work")
            if not exists(_work):
                mkdir(_work)
    
            _from = join(ymir, folder)
            _to = join(_work, folder)
    
            move(_from, _to)
            print("Moved folder {}".format(folder))
    
    
    def MoveLocale(locale):
        root = join(raw, locale)
    
        if locale == "locale":#P3ng3r
            for folder in listdir(root):
                _base = join(target, locale + "_" + folder)
                _from = join(raw, locale, folder)
                _to = join(_base, locale, folder)
    
                if not exists(_base):
                    mkdir(_base)
                    mkdir(join(_base, locale))
    
                move(_from, _to)
                print("Moving locale {}", folder)
    
        elif locale == "locales":#Astro
            for folder in listdir(root):
                move(join(root, folder), join(target, folder))
    
    
    __name__ = MoveFolders()

     

     

    • Metin2 Dev 2
    • Lmao 1
    • Good 3
    • Love 1
  11. Skip this part, you don't need it anymore. Scroll down.

    The game loop freezes when dragging/resizing the window. This is an attempt at fixing that.

     

    We'll open a thread and call "Process()" from there when we receive WM_ENTERSIZEMOVE and then shut it down when receiving WM_EXITSIZEMOVE, continuing our main game loop.

     

    There's also the option of creating a timer when entering WM_ENTERSIZEMOVE, calling "Process()" when receiving WM_TIMER and killing it when receiving WM_EXITSIZEMOVE, but there's quite a big delay till the timer starts and it's also not very reliable, so..

    Note: This is HIGHLY experimental, and it might result in data races and crash the client. Even though I tested it as good as I could and tried to make sure the main thread's loop doesn't resume before ending the future, it's still a possibility for that to happen when you least expect it.

     

    Video:

    Code:

    This is the hidden content, please
     or 
    This is the hidden content, please

    Many thanks to @limefor taking the time to test it.

    Good luck!

     

     

     

    UPDATE: Forget everything I gave you the last time, here's the complete fix:

    UPDATE2: Blocked right click as well, thanks @ CORKY

    If there's anything else that needs blocking/changing, let me know and I'll update the topic.

    Spoiler
    // PythonApplication.cpp
    // Search m_dwLastIdleTime(0),
    // Add m_IsMovingMainWindow(false),
    
    // Search 
    #ifndef _DEBUG
    	SetEterExceptionHandler();
    #endif
      
    // Add
    	m_InitialMouseMovingPoint = {};
    
    // Search
    void CPythonApplication::Loop()
    {
      ...
    }
    
    // Add before:
    void CPythonApplication::SetUserMovingMainWindow(bool flag)
    {
    	if (flag && !GetCursorPos(&m_InitialMouseMovingPoint))
    		return;
    
    	m_IsMovingMainWindow = flag;
    }
    bool CPythonApplication::IsUserMovingMainWindow() const
    {
    	return m_IsMovingMainWindow;
    }
    void CPythonApplication::UpdateMainWindowPosition()
    {
    	POINT finalPoint{};
    	if (GetCursorPos(&finalPoint))
    	{
    		LONG xDiff = finalPoint.x - m_InitialMouseMovingPoint.x;
    		LONG yDiff = finalPoint.y - m_InitialMouseMovingPoint.y;
    
    		RECT r{};
    		GetWindowRect(&r);
    
    		SetPosition(r.left + xDiff, r.top + yDiff);
    		m_InitialMouseMovingPoint = finalPoint;
    	}
    }
    
    
    // Search
    void CPythonApplication::Loop()
    {
    #ifdef PROFILING
    	Profiler::Instance().beginSession("session1");
    #endif
    
    	while (1)
    	{
    
    // Add
    		if (IsUserMovingMainWindow())
    			UpdateMainWindowPosition();
    
    // Looks like this:
    	while (1)
    	{
    		if (IsUserMovingMainWindow())
    			UpdateMainWindowPosition();
    
    		if (IsMessage())
    		{
    			if (!MessageProcess())
    				break;
    		}
    		else
    		{
    			if (!Process())
    				break;
    
    			m_dwLastIdleTime = ELTimer_GetMSec();
    		}
    	}

     

     

    Spoiler
    // PythonApplication.h
    // Find
    void Loop();
    
    // Add
    	bool IsUserMovingMainWindow() const;
    	void SetUserMovingMainWindow(bool flag);
    	void UpdateMainWindowPosition();
    
    // Go to the end and
    protected:
    	bool m_IsMovingMainWindow;//add this
    	POINT m_InitialMouseMovingPoint; // and this
    	int m_iCursorNum;

     

     

    Spoiler
    // PythonApplicationProcedure.cpp
    // Find
    case WM_EXITSIZEMOVE:
    {
    ...
    }
    
    // Add
    	case WM_NCLBUTTONDOWN:
    	{
    		switch (wParam)
    		{
    		case HTMAXBUTTON:
    		case HTSYSMENU:
    			return 0;
    		case HTMINBUTTON:
    			ShowWindow(hWnd, SW_MINIMIZE);
    			return 0;
    		case HTCLOSE:
    			RunPressExitKey();
    			return 0;
    		case HTCAPTION:
    			if (!IsUserMovingMainWindow())
    				SetUserMovingMainWindow(true);
    
    			return 0;
    		}
    
    		break;
    	}
    	
    	case WM_NCLBUTTONUP:
    	{
    		if (IsUserMovingMainWindow())
    			SetUserMovingMainWindow(false);
    		
    		break;
    	}
    
    	case WM_NCRBUTTONDOWN:
    	case WM_NCRBUTTONUP:
    	case WM_CONTEXTMENU:
    		return 0;

     

    • Metin2 Dev 116
    • Think 1
    • Good 20
    • Love 2
    • Love 47
  12. Spoiler

      

    10 minutes ago, Deso said:

     Here is my slightly refactored version.. 🤣

     

    #include <unordered_map>
    
    // Add a list of maps and their corresponding max distance values to a map.
    // This allows us to look up the max distance value for a given map more efficiently than using a series of if statements.
    std::unordered_map<std::string, float> mapMaxDistances = {
        {"metin2_map_n_flame_dragon", 6000.0f},
        {"metin2_12zi_stage", 5000.0f},
        {"metin2_map_defensewave", 5000.0f},
        {"metin2_map_miniboss_01", 5000.0f},
        {"metin2_map_miniboss_02", 5000.0f},
        {"metin2_map_mists_of_island", 5000.0f}
    };
    
    PyObject* appSetCameraMaxDistance(PyObject* poSelf, PyObject* poArgs)
    {
        float fMax;
        if (!PyTuple_GetFloat(poArgs, 0, &fMax))
            return Py_BuildException();
    
        const std::string c_rstrMapFileName = CPythonBackground::Instance().GetWarpMapName();
    
        // Look up the max distance value for the current map in the mapMaxDistances map.
        // If the map is not found in the map, the max distance value will be the default value of 0.0f.
        fMax = mapMaxDistances[c_rstrMapFileName];
    
        CCamera::SetCameraMaxDistance(fMax);
        return Py_BuildNone();
    }

     

     

    The fuck did you refactor?

     

    Thanks, Mali!

  13. This is the first version(made a month ago). No isolation from normal fishing or ON/OFF switch and no key exchange/validation, but it's working.

    Let me know if I forgot any assets/pieces of code and I'll update the repo.

    Code: 

    This is the hidden content, please
     or 
    This is the hidden content, please

     

    Little GIF:

    .gif

     

    Don't message me. If you have problems, post them here.

    Good luck!

    • Metin2 Dev 55
    • Good 15
    • Love 72
  14. No need for a description, here's the code:

    This is the hidden content, please
     or 
    This is the hidden content, please

    207033801-eb301906-1604-460c-93d7-27e89c

    Q: Is this the best way to do it? Is there a better way?

    A: Don't know, don't care. That's how I've done it, get over it.

     

    Q: Any checks you didn't add?

    A: There might be some stuff that I missed/forgot about(done it in a rush). If you notice something, let me know and I'll update the code accordingly.

     

    Q: It's not working for me. Support?

    A: Only in the topic(when I have time), don't fucking message me.

    • Metin2 Dev 57
    • Good 8
    • Love 1
    • Love 88
  15. On 12/5/2022 at 10:28 AM, Olimpion2 said:

    Thank you very much friend, it has already helped me 50%, I would like to put the option in the login and selection part too, if you can help me, I really appreciate it.

    Don't push it, the dude already gave you everything you asked for/needed. Read the root files, use your brain(if you have any), and do it yourself.

     

    If you can't read/write code at a basic level, you shouldn't be here, and that's a fact.

    Start here: https://wiki.python.org/moin/BeginnersGuide/NonProgrammers

    • Not Good 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.