Jump to content

Shogun

Premium
  • Posts

    1361
  • Joined

  • Days Won

    77
  • Feedback

    0%

Posts posted by Shogun

  1. Every once in a while, there's always the odd kid making fun about my age. I remember with a smile all the "why are you playing Metin when you should be having kids" back in the days I played, which sounds as ridiculous now as my parents asking if "those people on the screen" were "real people", except my parents had an excuse for the ignorance in the matter. And later on, after I started WoM2, how people was surprised that I actually knew my way around code or design even though I never went to university or followed any course on the subject.

     

    So here's the story behind it,. Many years before WoM, even before YMIR existed, I was part of an underground culture known as the demoscene, and it turns out that this month, it was accepted by the Finnish government for submission to the UNESCO as a candidate for inmaterial human heritage, so I thought it's a good time to talk about it.

     

    A demo, as its name says, is a demonstration. A game demo demonstrates what a game is capable of doing; and, likewise, the scene demos demonstrate what people are capable of doing. Coders, artists and music producers get together, trying to design a piece of art to please the audience. It may be deep, spiritual, funny; sometimes is completely abstract and purely a showcase of mathematical algorithms; sometimes it's the opposite and everything is subordinated to the design. There are no rules, and everything is done just for the sake of proving yourself and your group (team).

     

    You may have seen a demoscene production before - if you downloaded cracked software, sometimes they would come with a keygen or nocd program playing some cheerful chip music. That's what we call a cracktro - small intros placed by crackers in the software they unprotected, and that was how the whole thing started back in the eighties, when the only form of software distribution was mailing disks or tapes on envelopes.

     

    You may also have heard about LAN Parties where people used to gather to play Counter Strike, Battlefield and other games and, sometimes, win prizes -although nowadays they are kind of made obsolete by bigger and flashier esports events like ESL. Well, those LAN parties (the Gathering, Assembly, Euskal...) started as a place where the scene people would showcase their demos, intros (a small demo limited in size, usually to 64 Kb or 4), music or pixel art. And we still do, although we do it in separate "demo parties" where there's no gaming part.

     

    One of such events is the Revision 2020, which was to take place in Saarbrucken, Germany few days ago but was made online instead because of the infamous virus that keeps us bored enough to write posts like this. So, without further a do, it's time to stop reading this grandpa story you don't understand anyway and watch some mindblowing art! So here are the 1st, 2nd and 3rd qualified demos at the Revision 2020, freshly released this past weekend.

     

    (I really recommend you to download the executable files from Pouet as the quality is of course way better than in the video stream, which isn't nearly as mindblowing. This stuff is made for PC, not Youtube. Online video encoders choke with such high resolution, high fps content. Also don't worry about viruses, this is not the ubertoxic mt2 scene. We do this for fun.)

     

    1st - VX2 by Spectrals

    Download https://www.pouet.net/prod.php?which=85304

     

     

     

    2nd - Cathodoluminiscence by MFX

    Download https://www.pouet.net/prod.php?which=85305

     

     

     

    3rd - Bring it on by Cocoon

    Download https://www.pouet.net/prod.php?which=85317

     

     

    If you want to see more, be welcome to check the full list of productions from Revision 2020 (including retro systems) or even better, check the all time "best PC demo" rankings for an endless list of life changing computer art :)

     

    https://www.pouet.net/prodlist.php?type[0]=demo&platform[0]=Windows&page=1&order=thumbup

    • Metin2 Dev 1
    • Confused 2
    • Love 4
  2. As I said players don't just need to communicate with the server - it's a multiplayer game, so they also need to communicate with each other, even if it's done through the server.

     

    Which means your best bet is getting a server in a place where pings are as fair as possible for everyone.

     

    If we are talking about Europe and America, then New York, UK or France are your best bets. It depends on your priorities and how many players are in each contintent.

    • Love 1
  3. If you have ever had an incident on your server - cores crashing, filesystem getting full, lag ingame, or ddos attacks- you know that it can turn into detective work to find what is wrong, especially when we don't have a degree in CS. There are some nifty command line monitoring tools (glances, htop, atop come to mind) but when you have several server machines it can get quite frantic and besides - those tools do not offer a lot of flexibility.

     

    As we progress in the path to become a skilled server administrator (understanding server as in the machine and the software installed on it rather than in the Metin2 sense), it becomes necessary to use a remote monitoring tool that gives us some visibility on our systems. There is a myriad of paid options featuring flashy animated dashboards out there, but they mostly belong to the cash cow realm of SaaS which I try to stay away of. So today I am going to introduce you to a free monitoring tool -monit- and to its paid console addon, which for some reason the programmers decided to name mmonit, creating unnecessary confusion.

     

    You may think that there is already enough documentation out there about popular tools like this - but you're wrong. As well crafted as monit and mmonit are, the documentation is somewhat obscure, particularly when it comes to FreeBSD. So I wanted to write down my experience in getting this tool to work in the best server operating system there is. Yeah, because as much as we like mocking the Ymir programmers, those who worked in the original version were not stupid at all, and the fact that they chose the rock solid FreeBSD -which was a relatively new system back then- is a good proof of that.

     

    Part A: Monit

     

    So let's get into action and introduce you to Monit. Monit is a very configurable daemon that can check virtually anything on our system -bandwidth, running processes, disk usage...- or even run custom scripts that extend its capabilities, and send us an e-mail to alert when, for example, we are running out of space, or our game server crashes. Nifty isn't it? Here's how an e-mail from monit looks:

    Connection failed Service nginx 
    
    	Date:        Sat, 04 Apr 2020 18:05:26
    	Action:      alert
    	Host:        host.myserver.com
    	Description: failed protocol test [HTTP] at [www.myserver.com]:443 [TCP/IP TLS] -- HTTP: Error receiving data -- Operation timed out
    
    Your faithful employee,
    Monit

     

    Installing monit is easy - just run

    pkg install monit

    And then let's get our configuration ready.

    cp /usr/local/etc/monitrc.sample /usr/local/etc/monitrc
    
    ee /usr/local/etc/monitrc

    I will detail here the options we should concern ourselves about - you can leave the rest as default.

     

    First is the mail server which we are going to use to submit mail alerts; I entered here my own cPanel mailserver, where we previously whitelisted our IP (Exim Configuration/Access Control). If you don't have your own mail server, you can send the e-mail to sendmail on localhost.

    set mailserver mail.myserver.com,               # primary mailserver
                    localhost                   # fallback relay

    Next goes the e-mail address where we want to receive the alerts:

    set alert [email protected] not on { instance, action }

    And here we can configure the web interface. Here we set a port, user and password to connect. Simple isn't it?

    set httpd port 2812 and
        allow someuser:somepassword
    

    Finally we get to the substance - the monitoring rules. There are plenty of examples in the file, but I will drop my own configurations here as well, including a metin server which is what you're probably interested. This configuration is specific for FreeBSD (12 in my case but should be fine in any modern version)

    # Check overall system health
    check system $HOST
        if loadavg (1min) per core > 2 for 5 cycles then alert
        if loadavg (5min) per core > 1.5 for 10 cycles then alert
        if cpu usage > 75% for 2 cycles then alert
        if memory usage > 75% for 2 cycles then alert
        if swap usage > 75% for 2 cycles then alert
    
    # Web Server
    check process nginx with pidfile /var/run/nginx.pid
       start program = "/usr/local/etc/rc.d/nginx start"
       stop program = "/usr/local/etc/rc.d/nginx stop"
       if failed host www.mysite.com port 80 protocol http and request '/index.html' then alert
       if failed host patch.mysite.com port 80 protocol http and request '/index.php' then alert
    check process php-fpm with pidfile /var/run/php-fpm.pid
       start program = "/usr/local/etc/rc.d/php-fpm start"
       stop program = "/usr/local/etc/rc.d/php-fpm stop"
       if children > 30 then alert
    
    # Check network interface and usage. This would warn us about DDoS attacks that rely on
    # flooding the connection, or about an overloaded patch server.
    check network ix0 with interface ix0
       if failed link then alert
       if saturation > 75% for 2 cycles then alert
    
    # Check filesystem usage - so we don't run out of disk space unexpectedly
    check filesystem zroot/ROOT/default with path /
       if space usage > 75% then alert
    
    # Check metin2 game processes, so we will get alerts on a core crash
    check process db with pidfile /home/metin2/db/pid.db
      start program = "/home/metin2/db/run.sh"
      stop program = "/home/metin2/db/shutdown.sh"
      mode passive
    check process auth with pidfile /home/metin2/auth/pid.auth
      start program = "/home/metin2/auth/run.sh"
      stop program = "/home/metin2/auth/shutdown.sh"
      mode passive
     check process channel1_game1 with pidfile /home/metin2/channel1/game1/pid.game
      start program = "/home/metin2/channel1/game1/run.sh"
      stop program = "/home/metin2/channel1/game1/shutdown.sh"
      mode passive
    check process channel1_game2 with pidfile /home/metin2/channel1/game2/pid.game
      start program = "/home/metin2/channel1/game2/run.sh"
      stop program = "/home/metin2/channel1/game2/shutdown.sh"
      mode passive
    check process channel2_game1 with pidfile /home/metin2/channel2/game1/pid.game
      start program = "/home/metin2/channel2/game1/run.sh"
      stop program = "/home/metin2/channel2/game1/shutdown.sh"
      mode passive
    check process channel2_game2 with pidfile /home/metin2/channel2/game2/pid.game
      start program = "/home/metin2/channel2/game2/run.sh"
      stop program = "/home/metin2/channel2/game2/shutdown.sh"
      mode passive

     

    Note that I add "mode passive" because I do not want monit to restart the server if it's down; I only want the alert sent to me. If you want monit to do that, just remove the "mode passive" lines (as I did for nginx and php-fpm)

    Also note that channel1_game1 are just names I give them so I can recognize them in the web interface, what matters here is the pid file. Other than that, there are plenty of examples in that file to get you started.

     

    Once we are happy with our settings, save and add the following lime to /etc/rc.conf

    monit_enable="YES"

     

    And now it's showtime:

    service monit start

    If we set everything properly, we should start getting e-mail alerts on our defined events. It may take some finetuning for you to discover which loads are out of the ordinary for your server and you should be warned about. For example, a simple web server with a 1 Gbps connection having 25% saturation is not normal, but if that web server is being used as a patch server, then you will probably average more than that. You may also use the web interface, though it's pretty basic in monit.

     

    This is all regarding monit the free monitoring tool, but for me the most interesting is integrating this system with M/Monit - which is a paid app (60$ for 5 hosts) but with a lifetime license so no monthly payments to worry about. I will get to this soon as it's a perfect solution of you have a bunch of servers to take care of and integrates with FreeBSD and other OS perfectly.

     

    Part B: M/Monit

     

    As promised, here is the second part of the tutorial concerning M/Monit. M/Monit is a centralized server which collects data from any number of monit hosts and stores it to keep statistics, make alerts more visual. It also allows for stopping and starting services if we set a "Stop" and "Start" parameter for them in monitrc, and you can even show the output of a command from the process list using the "check program" directive in monitrc and hovering over the process name in the M/Monit list.

     

    Now it's when things get pretty, with pie charts, responsive interfaces and whatnot. Take a look at this beauty:

     

    134237mmonit1.jpg

     

    134237mmonit2.jpg

     

    134237mmonit3.jpg

     

    Now as I said at the beginning there's lots of pretty monitoring interfaces you can buy in the internet and M/Monit is not the prettiest but there's two things that make it stand out:

     

    1. It works perfectly with FreeBSD, as it integrates with monit which has been a standard package in FreeBSD for many years.

    2. It's not a SaaS cash cow charging you a fortune every month - you pay once and it's yours forever.

     

    So first thing you should get yourself a license here: https://mmonit.com/shop/

     

    As you can see it's 65€ for up to 5 hosts - lifetime. Those hosts do not need to be FreeBSD, it can be any mix of systems, but I will explain here how to install it on FreeBSD because their documentation, as it happens often, kind of ignores our OS, despite it being supported.

     

    While monit should be installed in every server you want to monitor, M/Monit only needs to be installed once, in any server you want (you could even install it in your own PC). Just make sure firewall rules allow traffic between the monit and mmonit instances (monit: port 2812; mmonit: 8080). This M/Monit server should be running a database server - I will assume you have MySQL but SQLite and PostgreSQL are supported too.

     

    (credit: I got some of these instructions from a post by SirDice in the official FreeBSD forum)

     

    Once you purchased the package extract it (replace the <X.X.X> with your version)

     

    tar -C /usr/local -zxvf mmonit-<X.X.X>-freebsd-x64.tar.gz
    ln -s /usr/local/mmonit-<X.X.X> /usr/local/mmonit

     

    As SirDice explains "The symlink allows you to keep the old versions and switch back in case of problems. ". So whenever you want to install a new version you just need to delete the symlink and then follow these same steps, copying over your configuration to the new folder.

     

    Now edit the config:

     

    ee /usr/local/mmonit/conf/server.xml

     

    The parts we should edit:

     

           <Connector address="x.x.x.x" port="8080" processors="10" />
     

    Change that IP for that server's public IP - this is where mmonit will listen for connections.

     

           <Engine name="mmonit" defaultHost="mmonit.mydomain.com" fileCache="10MB">
     

    Here we could use the same IP again or, if you want to use a DNS entry instead such as mmonit.mydomain.com, place it here. This is the hostname that we will use to connect to the interface.

     

    Now create a database "mmonit" in your MySQL server and a local user like this:

     

    CREATE DATABASE mmonit;

    CREATE USER 'mmonit'@'localhost' IDENTIFIED BY 'mmonit';

    GRANT ALL PRIVILEGES ON mmonit.* TO 'mmonit'@'localhost';

     

    and uncomment/edit the following lines in Server.xml:

     

             <Realm url="mysql://mmonit:mmonit@localhost/mmonit"
                      minConnections="5"
                      maxConnections="25"
                      reapConnections="300" />

     

    Another line to change here is:

     

               <Host name="mmonit.mydomain.com" appBase="." >

     

    Here we should replace it once again with the hostname we defined earlier or the server's IP.

     

    Finally at the end of the file you should paste the license information you got when purchasing mmonit.

     

    Now let's add a startup script for the service on /usr/local/etc/rc.d/mmonit

    #!/bin/sh
    
    # PROVIDE: mmonit
    # REQUIRE: DAEMON
    # KEYWORD: shutdown
    
    #
    # Add the following line to /etc/rc.conf to enable M/Monit
    #
    # mmonit_enable="YES"
    
    . /etc/rc.subr
    
    name=mmonit
    rcvar=mmonit_enable
    
    load_rc_config "$name"
    
    : ${mmonit_enable:="NO"}
    
    command="/usr/local/mmonit/bin/mmonit"
    command_args=""
    start_precmd="mmonit_checkconfig"
    stop_cmd="mmonit_stop"
    start_cmd="mmonit_start"
    
    mmonit_checkconfig () {
            echo "Performing sanity check on M/Monit configuration:"
            eval ${command} ${mmonit_flags} -t
    }
    
    mmonit_start () {
            echo "Starting M/Monit:"
            eval ${command} ${mmonit_flags} start
    }
    
    mmonit_stop () {
            echo "Stopping M/Monit:"
            eval ${command} stop
    }
    
    run_rc_command "$1"

     

    Remember to chmod 777 this file after you save it, as it is supposed to be an executable.

     

    Now and before we run the service, it's time to configure our monit (not mmonit) instances that we set up in the first part to communicate with mmonit. So go back to /usr/local/etc/monitrc in each server where you installed it and uncomment & edit the following lines:

     

    set mmonit http://monit:<somepassword>@mmonit.mydomain.com:8080/collector
     

    Also in order to issue commands from MMonit to Monit, such as stopping a service remotely, we need to do the following (once again if you don't have your own domain you can replace mmonit.mydomain.com with the M/Monit server IP)

     

    set httpd port 2812 and
        allow 127.0.0.1      
        allow mmonit.mydomain.com
        allow monit:<somepassword> 

     

    In both cases we replace mmonithost with either the IP address or the domain we set previously for mmonit, and <somepassword> with a secure password - this is used for monit and mmonit to communicate with each other, so we don't need to remember it ourselves.

     

    Now let's go back once again to the server where we just installed M/Monit and add this in /etc/rc.conf to auto start mmonit.

     

    mmonit_enable="YES" 

     

    And start the service with:

     

    service mmonit start

     

    Now we should be able to browse to the IP or hostname we configured previously.

     

    http://mmonit.mydomain.com:8080/

     

    The default user and password are admin:swordfish, you should of course change this inmediately from the web interface itself (Admin menu > Users)

     

    If everything is done properly, we will get those pretty statistics right in our browser. You can read more about mmonit in the manual:

     

    https://mmonit.com/documentation/mmonit_manual.pdf

    • Love 14
  4. 8 hours ago, Mali61 said:

    15 year old game bla blaa. This is not an excuse.

    Just go another forums and see " 15 year old game"

    How does the forum develop if we do not criticize?

     

    When i login this forum, i only see a dead forum.

    Forum can create a share team.

    They can take good topics from other forums and share them here as everyone does.

    With this way we can keep the forum alive

     

    It's the other forums that copy our threads dude. The most knowledgeable people are here, end of story.

    • Love 1
  5. On 4/2/2020 at 12:14 PM, Mali61 said:

    You should look for new users too

     

    Considering that Metin2 is 15 years old I'd say this forum is very active with quality content and the work of the new team has a lot to do with this. What else do you expect them to do? Spam the forum link with bots ingame?

    • Love 6
  6. 10 minutes ago, Ace said:

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

     

    This feature is there if you have a map and do not know which objects this map uses or

    which are missing. If you have e.g. 100 objects but only 5 of them are used, it is stupid to

    pack all 100 with them. don't you think?

     

    Thank you Artur for this code.

     

    Hi, in the video I see that it finds the missing ones. That's not of much use normally as you would have no way to know which objects those YPRTs represent. You can't delete them from the map either because the tool is not doing that for you or telling you where they are (though it would be trivial to find them with Notepad++ and similar tools)

     

    Finding the unused ones is a completely different thing as it would involve

     

    1) searching every map folder and building a list of all unique YPRTs found

    2) compare said list against property and build a list of unused properties, but only those  which point to zone or tree  -properties can also point to effect, guild etc., but only tree and zone can sort of guarantee us we aren't going to delete something we shouldn't, as long as we built our client following the "guidelines"

    3) compare against zone and build a list of unused gr2, spt, mde files

     

    That would allow us to remove unused gr2, mde and mdatr files, but it still doesn't solve the question of which textures we can delete - unless we program reading of those paths off the gr2/mde/spt files, which would not be trivial.

     

    Anyhow, here is, in case it's of any use, a python 2.7 script I made that moves all USED terrainmaps to a new folder (needs textureset and terraimaps to be a subfolder of the working dir). Disclaimer: I don't really know python.

     

    import os
    import re
    import string
    import shutil
    import sys
    
    ct = 0
    usedimg = []
    usedsets = []
    list = []
    
    class cd:
        """Context manager for changing the current working directory"""
        def __init__(self, newPath):
            self.newPath = os.path.expanduser(newPath)
    
        def __enter__(self):
            self.savedPath = os.getcwd()
            os.chdir(self.newPath)
    
        def __exit__(self, etype, value, traceback):
            os.chdir(self.savedPath)
    
    def cleanValue(val):
    	val = val.replace('\\', '/')
    	val = val.strip(' \t\n"')
    	val = val.lower()
    	return val
    
    def copyFile(src, dest):
        try:
            shutil.copy(src, dest)
            return True
        # eg. src and dest are the same file
        except shutil.Error as e:
            print('Error copying ' + src + ' to ' + dest + ': %s' % e)
        # eg. source or destination doesn't exist
        except IOError as e:
            print('Error copying ' + src + ' to ' + dest + ': %s' % e.strerror)
        return False
    # Read the tab-separated value of a parameter "param" in all files named "fname" (can be an extension) in folder "folder"
    
    def SaveParams(param,fname,folder,list):
    	for path, subdirs, files in os.walk(folder):
    		for filename in files:
    			if filename.lower() == fname.lower() or (fname.startswith('.') and filename.endswith (fname)):
    				f = os.path.join(path, filename)
    				with open(f, "rt") as current:
    					for line in current:
    						lcline = line.lower() 
    						lcparam = param.lower()
    						if lcparam in lcline:
    							# strip tabs and split values
    							value = line.rstrip('\t\n')
    							# get parameter value
    							list.append(value)
    
    # Read a value with the order number "order" within a parameter block "block" in all files named "fname" (can be an extension) in folder "folder" which are also in list "compare"
    
    def SaveParamsFromBlock(block,order,fname,folder,list,compare):
    	for path, subdirs, files in os.walk(folder):
    		for filename in files:
    			if filename in compare and (filename.lower() == fname.lower() or (fname.startswith('.') and filename.endswith (fname))):
    				countblock = -1
    				f = os.path.join(path, filename)
    				with open(f, "rt") as current:
    					for line in current:
    						lcline = line.lower() 
    						lcblock = block.lower()
    						if countblock == order:
    							list.append(line)							
    							countblock = -1
    						elif lcline.startswith(lcblock):
    							countblock = 0
    						elif countblock >= 0:
    							countblock = countblock + 1
    
    try:
    	os.makedirs('terrainmaps_release')
    except:
    	shutil.rmtree('terrainmaps_release')
    	os.makedirs('terrainmaps_release')
    
    print "This script copies to terrainmaps_release only the textures which are actually listed in textureset files."
    print ""
    print "Scanned: maps, maps_indoor"
    select = raw_input("Press any key to start, v for verbose, e to exit")
    if str(select) == "e":
    	sys.exit()
    
    # Get all the texturesets used in our maps
    
    SaveParams('TextureSet','Setting.txt','maps',usedsets)
    SaveParams('TextureSet','Setting.txt','maps_indoor',usedsets)
    SaveParams('TextureSet','Setting.txt','maps_special',usedsets)
    #SaveParams('TextureSet','Setting.txt','maps_test',usedsets)
    
    # Extract the filename part of the used TextureSet paths and write it back to the list
    
    for idx,val in enumerate(usedsets):
    	val = cleanValue(val)
    	parts = re.split('/', val.lower())
    	# check its actually a terrainmaps path
    	usedsets[idx] = parts[-1]
    
    # Fetch a list of the textures used in the sets used
    
    SaveParamsFromBlock('Start Texture',0,'.txt','textureset',usedimg,usedsets)
    
    # Copy the textures used in textureset_release
    
    for idx,val in enumerate(usedimg):
    	# check its actually a terrainmaps path
    	if  "terrainmaps" not in val:
    		print "Non-terrainmaps path: " + val
    	else:
    		val = cleanValue(val)
    		val = val[len('d:/ymir work/terrainmaps/'):]
    		usedimg[idx] = val.lower()
    		srcPath = 'terrainmaps/' + usedimg[idx]
    		destPath = 'terrainmaps_release/' + usedimg[idx]
    		if str(select) == "v":
    			print "Copy " + srcPath + " to " + destPath
    		if not os.path.isdir(os.path.dirname(destPath)):
    			os.makedirs(os.path.dirname(destPath))
    		if copyFile(srcPath, destPath):
    			ct = ct + 1
    		
    print "Total " + str(ct) + " textures copied in terrainmaps_release"
    raw_input("Press any key to exit")

     

    Tagging @PACI here he knows why

     

    • Love 3
  7. I don't see why it shouldn't work.

     

    By the way if you run a live server and have problems with the server lagging at backup time, here's a solution

    $MYSQLDUMP -u $MYSQL_USER -p$MYSQL_PASS $db | $GZIP -9 | cstream -t 16m > $LOCAL_FOLDER/$FILE

     

    Installing cstream (pkg install cstream) will allow you to set a bandwidth for the dump, in this case I set it at 16 mb per second. Tune to your liking.

     

    There are other issues related to backing up a live server though, mainly the consistency - while we are backing up something, something else may get updated creating an inconsistency or worse,corrupting the table. Also MyISAM tables get locked during a backup, potentially crashing or lagging the game in the meantime. Consider switching to InnoDB.

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