Jump to content

eressea

Legendary Member
  • Posts

    534
  • Credits

  • Joined

  • Last visited

  • Days Won

    8
  • Feedback

    0%

Posts posted by eressea

  1. Update 2019-01-14:

     

    - fixed server crash, you should update as soon as possible

    - rewritten old parsers to new style (Boost.Spirit) parser

    - fixed calls to wcstol (NCsoft guys don't reset errno correctly so zero value may look like completely wrong value) which fixes error message about invalid eventdata.ini format

    - added custom static boss respawn feature (see examples)

     

    http://download.l2shrine.com/MyExt64.dll

     

  2. On 12/7/2018 at 4:58 PM, rteshima said:

    uhh so complicated: / .. It might be that I'm not working because they are advext files?

     

    I replied you in mail but as someone else might need it, I'll copy my response here as well:

     

     

    Hi, it should run on Win Vista and newer and the single input NASC file has to be UTF-16LE.

     

    I personally use split AI structure which looks like this

     

    C:/l2/ai-src/default_npc.nasc

    C:/l2/ai-src/default_npc/citizen.nasc

    C:/l2/ai-src/default_npc/citizen/merchant.nasc

    C:/l2/ai-src/default_npc/citizen/merchant/bandor.nasc

    ...

     

    all these files are in UTF-8 without BOM (Byte Order Mask)

     

    I also have NASC there:

     

    C:/l2/nasc/compile.bat

    C:/l2/nasc/l2npc/l2npc.exe

    ...

     

    I join it, recode it to UTF-16LE and compile it with C:/l2/make.py:

     

    #!/usr/bin/env python
    
    # (C) 2017 L2Shrine.com
    
    # Usage:
    #
    # If you need just some classes, run "make.py" and let it compile everything that's not up to date
    # If you need to compile whole ai to get full ai.obj for server, run "make.py all"
    
    from os import walk, stat, getcwd, system, mkdir, unlink
    from codecs import open
    from sys import stderr, argv
    from glob import glob
    
    makeAll = False
    if len(argv) == 1:
        pass
    elif len(argv) == 2:
        if argv[1] == "all":
            makeAll = True
        else:
            print >> stderr, "Usage: %s [all]" % (argv[0], )
            raise SystemExit(1)
    else:
        print >> stderr, "Usage: %s [all]" % (argv[0], )
        raise SystemExit(1)
    
    if makeAll:
        aiFilename = "ai"
    else:
        aiFilename = "tmp"
    
    cwd = getcwd()
    
    def createPath(s):
        if s.startswith(u"\\\\?\\"):
            return s.replace("/", "\\")
        return u"\\\\?\\%s\\%s" % (cwd, s.replace("/", "\\"), )
    
    files = []
    
    for path, dirnames, filenames in walk(createPath("ai-src")):
        for i in filenames:
            srcPath = createPath("%s/%s" % (path, i, ))
            objPath = createPath("%s/%s" % (path[:len(cwd)+4] + path[len(cwd)+4:].replace("\\ai-src", "\\ai", 1), i.replace(".nasc", ".txt"), ))
            statSrc = stat(srcPath)
            try:
                if makeAll: raise Exception()
                statObj = stat(objPath)
            except:
                statObj = None
            if statObj == None or max(statSrc.st_ctime, statSrc.st_mtime) >= max(statObj.st_ctime, statObj.st_mtime):
                files.append(srcPath)
    
    if not files:
        print "Everything up to date"
        raise SystemExit(0)
    
    try:
        unlink("%s.obj" % (aiFilename, ))
    except:
        pass
    fw = open("%s.nasc" % (aiFilename, ), "w", "utf-16le")
    
    required = set(files)
    written = set()
    
    if not makeAll:
        print >> stderr, "Going to compile:"
    
    for i in files:
        if not makeAll:
            print >> stderr, "    %s" % (i.replace("\\", "/").split("/")[-1], )
        parts = i[len(createPath("ai-src/")):].replace("\\", "/").split("/")
        for j in xrange(len(parts)):
            if j != len(parts) - 1:
                filename = createPath("ai-src/%s.nasc" % ("/".join(parts[:j+1]), ))
            else:
                filename = createPath("ai-src/%s" % ("/".join(parts[:j+1]), ))
    
            if filename not in written:
                fw.write(open(filename).read())
                written.add(filename)
    
    fw.close()
    
    print >> stderr, "Compiling %d sources..." % (len(files), )
    
    result = system("cd nasc && compile.bat ..\\%s.nasc" % (aiFilename, ))
    
    err = glob("nasc/l2npc/log/err/*-01-npc*.log")
    if err and len(open(err[0], "r").read()) > 0 or result > 0:
        print >> stderr, "Compilation failed"
        raise SystemExit(1)
    
    curClass = None
    fw = None
    classes = [{}, {}]
    outputDir = "ai"
    for line in open("%s.obj" % (aiFilename, ), "r", "utf-16le"):
        line = line.strip("\n").strip("\r")
        if line.startswith("class"):
            if curClass == None:
                lineSplit = line.split()
                curClass = lineSplit[2]
                path = []
                if lineSplit[4] != "(null)":
                    classes[int(lineSplit[1])][curClass] = lineSplit[4]
                    parent = lineSplit[4]
                    while True:
                        path.append(parent)
                        parent = classes[int(lineSplit[1])].get(parent)
                        if parent == None:
                            break
                path.append(outputDir)
                path.reverse()
                try:
                    mkdir(createPath("/".join(path)))
                except WindowsError, e:
                    if e.winerror != 183:
                        raise
                path.append(curClass)
                srcFilename = u"%s.nasc" % (createPath("/".join(path)), )
                srcFilename = srcFilename[:len(cwd)+4] + srcFilename[len(cwd)+4:].replace("%s\\" % (outputDir, ), "ai-src\\", 1)
                if srcFilename in required:
                    filename = "%s.txt" % (createPath("/".join(path)), )
                    fw = open(filename, "w")
            else:
                curClass = None
    
        if fw != None:
            print >> fw, line
    
        if curClass == None and fw != None:
            fw.close()
            fw = None
    
    if not makeAll:
        #unlink("%s.nasc" % (aiFilename, )) # uncomment this if you don't need single NASC file
        #unlink("%s.obj" % (aiFilename, )) # uncomment this if you don't need ai.obj file
        pass
    
    print >> stderr, "Done!"

     

  3. On 12/5/2018 at 12:38 AM, rteshima said:

    The decompiler could execute it and modify the files that I wanted, but the compiler does not work for me.

     

    You need one single NASC source file in UTF-16LE encoding, then it should work fine. If you're using split and/or UTF-8 options in decompiler, you'll have to write some script that will join and recode that into one single UTF-16LE file (in correct order).

  4. 14 hours ago, maxicroma said:

    The Hauthd have a reload option ,there its some way to call this function every x time ?

     

    Probably there is some way but this is much easier:

    #!/usr/bin/env python
    
    from urllib import urlopen
    from json import loads
    from sys import stderr
    from time import sleep
    from subprocess import Popen
    from socket import inet_aton
    from threading import Thread
    
    period = 60.0 # seconds
    serverId = 1 # server ID
    sqlcmd = "C:\\Program Files (x86)\\Microsoft SQL Server\\Client SDK\\ODBC\\130\\Tools\\Binn\\SQLCMD.EXE" # put correct path here!
    server = "(local)\SQLExpress" # put correct server string here!
    database = "lin2db" # database name
    hauthd = "C:\\l2\\auth\\hauthd.exe" # put correct path here!
    
    class HauthdThread(Thread):
    	def __init__(self):
    		Thread.__init__(self)
    		self.hauthdProcess = None
    		self.doRun = True
    
    	def run(self):
    		while self.doRun:
    			self.hauthdProcess = Popen([hauthd])
    			self.hauthdProcess.wait()
    			self.hauthdProcess = None
    
    	def stop(self):
    		self.doRun = False
    		if self.hauthdProcess != None: self.hauthdProcess.kill()
    
    	def restart(self):
    		self.hauthdProcess.kill()
    
    currentIp = None
    ipUpdated = False
    hauthdThread = None
    
    try:
    	while True:
    		try:
    			newIp = loads(urlopen("https://api.ipify.org?format=json").read())["ip"]
    			if newIp != currentIp:
    				inet_aton(newIp) # check IP
    				print >> stderr, "New IP address:", newIp
    				currentIp = newIp
    				isUpdated = False
    		except KeyboardInterrupt, e:
    			raise
    		except:
    			print >> stderr, "Couldn't get current IP address, will retry later"
    			sleep(period)
    			continue
    
    		if isUpdated:
    			sleep(period)
    			continue
    
    		try:
    			popen = Popen([sqlcmd, "-S", server, "-d", database, "-Q", "UPDATE dbo.server SET ip='%s' WHERE id=%s" % (currentIp, serverId, )], shell = True)
    			popen.wait()
    			isUpdated = True
    			if hauthdThread == None:
    				hauthdThread = HauthdThread()
    				hauthdThread.start()
    			else:
    				hauthdThread.restart()
    		except KeyboardInterrupt, e:
    			raise
    		except:
    			print >> stderr, "Couldn't update IP address, will try later"
    
    		sleep(period)
    except:
    	hauthdThread.stop()
    	hauthdThread.join()
    	raise
    

     

  5. #!/usr/bin/env python
    
    from urllib import urlopen
    from json import loads
    from sys import stderr
    from time import sleep
    from subprocess import Popen
    from socket import inet_aton
    
    period = 60.0 # seconds
    serverId = 1 # server ID
    sqlcmd = "C:\\Program Files (x86)\\Microsoft SQL Server\\Client SDK\\ODBC\\130\\Tools\\Binn\\SQLCMD.EXE" # put correct path here!
    server = "(local)\SQLExpress" # put correct server string here!
    database = "lin2db" # database name
    
    currentIp = None
    ipUpdated = False
    
    while True:
    	try:
    		newIp = loads(urlopen("https://api.ipify.org?format=json").read())["ip"]
    		if newIp != currentIp:
    			inet_aton(newIp) # check IP
    			print >> stderr, "New IP address:", newIp
    			currentIp = newIp
    			isUpdated = False
    	except KeyboardInterrupt, e:
    		raise
    	except:
    		print >> stderr, "Couldn't get current IP address, will retry later"
    		sleep(period)
    		continue
    
    	if isUpdated:
    		sleep(period)
    		continue
    
    	try:
    		popen = Popen([sqlcmd, "-S", server, "-d", database, "-Q", "UPDATE dbo.server SET ip='%s' WHERE id=%s" % (currentIp, serverId, )], shell = True)
    		popen.wait()
    		isUpdated = True
    	except KeyboardInterrupt, e:
    		raise
    	except:
    		print >> stderr, "Couldn't update IP address, will try later"
    
    	sleep(period)

     

    EDIT: You'll also need to restart hauthd somehow...

  6. Just for sure (it doesn't sound familiar for me), is it l2off platform (not java)?

     

    If it's l2off and you're still in October olympiad season, you can shutdown l2server and cached and update the last row of lin2world.dbo.olympiad table with following values:

     

    season_start_time=1525132800

    bonus1_sec=604800

    bonus2_sec=1209600

    bonus3_sec=1814400

    bonus4_sec=2419200

    nominate_sec=2678400

     

    (season_start_time value is for UTC, if you're in different time zone, add or substract 3600 for each hour, e.g. for UTC+2 add 7200, for UTC-1 substract 3600)

     

    then start cached and l2server again and olympiad season should end almost immediately as it starts (and new season should start)

  7. Moved to correct section.

     

     

     

    EDIT: As for the no-trade zones, this can be found in leaked Gracia Final (in areadata.txt):

     

    area_begin name=[giran_town_shop13] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{83845;147579;-3400;-2400};{83845;149611;-3400;-2400};{82712;149553;-3464;-2400};{82723;147649;-3464;-2400}} area_end
    area_begin name=[giran_town_shop14] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{82723;147649;-3464;-2464};{82710;147886;-3464;-2464};{80904;147892;-3464;-2464};{80905;147650;-3464;-2464}} area_end
    area_begin name=[giran_town_shop15] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{81451;147699;-3464;-2464};{81696;147699;-3464;-2464};{81684;143459;-3528;-2528};{81444;143429;-3536;-2536}} area_end
    area_begin name=[giran_town_shop16] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{81438;146977;-3528;-2528};{81435;146827;-3528;-2528};{81068;146830;-3528;-2528};{81052;147001;-3528;-2528}} area_end
     

    and we use this on L2 Shrine:

     

    area_begin name=[giran_town_shop_restrict1] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{82956;147657;-3600;-3000};{82956;149557;-3600;-3000};{82707;149557;-3600;-3000};{82707;147657;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict2] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{82707;147657;-3600;-3000};{80908;147657;-3600;-3000};{80908;147895;-3600;-3000};{82707;147895;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict3] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{80908;147895;-3600;-3000};{80908;149557;-3600;-3000};{81153;149557;-3600;-3000};{81153;147895;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict4] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{81153;149557;-3600;-3000};{82707;149557;-3600;-3000};{82707;149313;-3600;-3000};{81153;149313;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict5] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{85825;147947;-3600;-3000};{85825;147073;-3600;-3000};{83596;147073;-3600;-3000};{83596;147947;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict6] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{83085;147468;-3600;-3000};{83773;147468;-3600;-3000};{83773;149771;-3600;-3000};{83085;149771;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict7] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{83773;149273;-3600;-3000};{83773;149771;-3600;-3000};{85106;149771;-3600;-3000};{85106;149273;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict8] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{83085;149566;-3600;-3000};{82956;149566;-3600;-3000};{82956;147657;-3600;-3000};{83085;147657;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict9] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{81664;147657;-3600;-3000};{81664;146789;-3600;-3000};{81422;146789;-3600;-3000};{81422;147657;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict10] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{81422;147032;-3600;-3000};{80564;147032;-3600;-3000};{80564;146789;-3600;-3000};{81422;146789;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict11] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{80564;146789;-3600;-3000};{80564;146353;-3600;-3000};{80862;146353;-3600;-3000};{80862;146789;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict12] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{81990;147657;-3600;-3000};{81990;147467;-3600;-3000};{82211;147467;-3600;-3000};{82211;147657;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict13] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{80908;148723;-3600;-3000};{80908;148517;-3600;-3000};{80440;148517;-3600;-3000};{80440;148723;-3600;-3000}} area_end
    area_begin name=[giran_town_shop_restrict14] map_no = {22;22} type=peace_zone blocked_actions={priv_store;priv_rstore} range = {{81671;149557;-3600;-3000};{81413;149557;-3600;-3000};{81413;149982;-3600;-3000};{81671;149982;-3600;-3000}} area_end
     

    • Like 1
  8. 2 hours ago, Anarchy said:

    yeah it's a pretty ancient bug that one, caused all kinds of havoc back in the like c2-c4 days before people actually figured out what it was, any c4-based ext will have it fixed via amped

     

    I've forgot about amped - this strategy of using two extenders at once seemed weird to me so I didn't care much about it :D

    Still not fixed in leaked H5 and GD... maybe still not fixed on offic server :D

  9. 45 minutes ago, xxdem said:

    Can you enlighten me a bit? Why we need to cache all these sessions on the map? Even if we do, what would the average n lenght be on an official NCSoft server?

     

    I'm not sure about purpose of the second map (I just know it's there and that it contains all account IDs since server start, maybe I'll dig bit more into it later), on retail server it will be big (surely 10k+)... That will be big difference between O(n) and O(log n). Probably it can be omitted - but it would probably have some performance impact.

  10. 5 minutes ago, xxdem said:

    imho I would just go O(n) with an array of struct{int accountId, int sessionId} and perform a search or something similar, it doesn't seem that the n will ever be huge on this case, I could be wrong

     

    That's true for the first map (accountId -> sessionId), it usually contains just few items. But the second map contains all account IDs that were logged since last server start so O(n) would be bad

×
×
  • Create New...