Jump to content

Idk, some script to automatically add missing functions to the client source from root meta(and mark the ones that don't exist anymore)


Recommended Posts

  • Contributor
Posted (edited)

Sup girls,

 

I was curious about what's changed in the official client and figured I'll make a script for it to avoid checking functions manually.

Note: For both your mental and physical health, don't read the code, I made it in an hour or something xDD

 

Works with these:

 

.png

 

Code:
 

Spoiler
from os import listdir, mkdir
from os.path import exists, join, isdir
from shutil import move, copytree
import re

builtins = "builtins/"
userInterface = "Userinterface/"

MISSING_FUNCTIONS = 1
REMOVED_FUNCTIONS = 2

# MISSING_FUNCTIONS_START

# It'll match whatever string is on the same line with METH_VARARGS
# and it'll end when it hits the first NULL
def AddFunctionToCppModuleIfDoesntExist(cppFilePath, moduleName, functionName):
    # print("Searching {} for module {} in {}".format(functionName, moduleName, cppFilePath))
    
    cppFile = open(cppFilePath, "r")
    line = 0
    startLine = 0
    endLine = 0

    lines = cppFile.readlines()

    for cppLine in lines:
        found = cppLine.find("METH_VARARGS")
        foundEnd = cppLine.find("NULL")
        if startLine == 0 and found > 0:
            startLine = line
        elif startLine > 0 and foundEnd > 0:
            toInsert = "\t\t// { \"" + functionName + "\", " + moduleName + functionName + ", METH_VARARGS }, // AUTOINSERT_FROM_SCRIPT\n"
            lines.insert(line, toInsert)

            cppFile.close()
            cppFile = open(cppFilePath, "w")
            cppFile.writelines(lines)
            cppFile.close()

            # endLine = line
            # print(toInsert)
            # # print("DIDN'T FIND {} IN Cpp file {} starts {} ends {}".format(functionName, cppFilePath, startLine, endLine))

            return

        line += 1

        pattern = r'{\s*"([^"]+)",'
        match = re.search(pattern, cppLine)
        if match:
            result = match.group(1)
            if result == functionName:
                # print("Found {}".format(functionName))
                break

    # print("Finished {}".format(moduleName))
    cppFile.close()


# It'll match whatever's after 'name' and end when it finds the first }],
def ParseBuiltin(cppFilePath, module, pyDictFile):
    # Go through all the lines of the py file
    pyFile = open(pyDictFile)
    for pyLine in pyFile.readlines():
        pattern = r"'name': '([^']*)'"
        match = re.search(pattern, pyLine)
        if match:
            result = match.group(1)
            # print("Found result {} ".format(result))

            # then search in the cpp file
            AddFunctionToCppModuleIfDoesntExist(cppFilePath, module, result)

        if pyLine.find("}],") > 0:
            break

    pyFile.close()

    # print("Doing cpp {}, pyDict {} ".format(cppFilePath, pyDictFile))

# MISSING_FUNCTIONS_END



# REMOVED_FUNCTIONS_START

def FunctionExistsInDump(pyDictFilePath, functionName):
    pyFile = open(pyDictFilePath)
    for pyLine in pyFile.readlines():
        pattern = r"'name': '([^']*)'"
        match = re.search(pattern, pyLine)
        if match:
            result = match.group(1)
            if result == functionName:
                return True

        if pyLine.find("}],") > 0:
            break

    pyFile.close()
    return False

def ParseCpp(cppFilePath, pyDictFilePath):
    cppFile = open(cppFilePath, "r")
    line = 0
    startLine = 0
    changedSomething = False

    lines = cppFile.readlines()

    for cppLine in lines:
        found = cppLine.find("METH_VARARGS")
        foundEnd = cppLine.find("NULL")
        if startLine == 0 and found > 0:
            startLine = line
        elif startLine > 0 and foundEnd > 0:
            break

        pattern = r'{\s*"([^"]+)",'
        match = re.search(pattern, cppLine)
        if match:
            result = match.group(1)
            if cppLine.find("AUTOINSERT_FROM_SCRIPT") == -1 and not FunctionExistsInDump(pyDictFilePath, result):
                changedSomething = True
                lines[line] = lines[line].replace("\n", "") + " // AUTOINSERT_FROM_SCRIPT: No official function.\n"
                # print("Function {} doesn't exist in {}".format(result, pyDictFilePath))

        line += 1

    # print("Finished")
    cppFile.close()
    if changedSomething:
        cppFile = open(cppFilePath, "w")
        cppFile.writelines(lines)
        cppFile.close()

# REMOVED_FUNCTIONS_END

def GetPathToPyDictFileFromModuleName(moduleName):
    possiblePrefixes = ["", "m2"]
    possibleSuffixes = [".dict.py", "m2g2.dict.py", "m2g.dict.py"]
    pathToPyFile = ""

    for prefix in possiblePrefixes:
        for suffix in possibleSuffixes:
            pathToPyFile = join(builtins, prefix + moduleName + suffix)
            if exists(pathToPyFile):
                return pathToPyFile

    return ""

# It'll match whatever is in Py_InitModule
def ProcessModuleNames(how):
    for cppFile in listdir(userInterface):
        pathToFile = join(userInterface, cppFile)

        if (isdir(pathToFile)):
            continue

        file = open(pathToFile)

        try:
            for line in file.readlines():
                if line.find("Py_InitModule") > 0:
                    # print(line)

                    pattern = r'Py_InitModule\("([^"]+)",'
                    match = re.search(pattern, line)

                    if match:
                        # Extract the content within the first pair of quotes
                        result = match.group(1)
                        # print(result)

                        pathToPyFile = GetPathToPyDictFileFromModuleName(result)
                        if pathToPyFile == "":
                            print("Builtin dump file doesn't exist for module {}".format(result))
                            continue

                        if how == MISSING_FUNCTIONS:
                            ParseBuiltin(pathToFile, result, pathToPyFile)

                        elif how == REMOVED_FUNCTIONS:
                            ParseCpp(pathToFile, pathToPyFile)

                        else:
                            print("The fuck do you want me to do?")
                        
                        # return
                    else:
                        print("No match found")
        except:
            continue

        file.close()


# Parse the dumps and add the functions that don't exist in the client source
def ProcessMissingFunctions():
    ProcessModuleNames(MISSING_FUNCTIONS)


# Parse the client source and mark the functions that don't exist in the dumps
def ProcessRemovedFunctions():
    ProcessModuleNames(REMOVED_FUNCTIONS)

ProcessMissingFunctions()
ProcessRemovedFunctions()

 

 

Can the script be improved? Yyyeah, but it runs in a second so I don't really give a shit.

If something's broken, let me know.

Have fun

 

Edit: Forgot to update the paths in 'ProcessModuleNames'

Edit2: Made it compatible with modules starting with m2, like m2netm2g

Edited by Amun
Fix
  • Metin2 Dev 2
  • Confused 1
  • Good 3
  • Love 2
Link to comment
Share on other sites

×
×
  • 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.