Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Launcher/updater available in the forum

Newbie Spellweaver
Joined
Sep 1, 2021
Messages
10
Reaction score
0
Good afternoon, everyone. Search by tag "Launcher and update" can find just a lot of ready-made developments from the time of the dinosaurs or unworkable links. I want to clarify if there is a less recent development of lunchers to update any game, by generating sha1 or md5, comparing files on the client and the server, and downloading new files accordingly. unzip will not work, because I can not understand what files have been changed in the game client between versions.

P.S. it's easy to do it yourself and blahblahblah please don't write. It's easier for me to change a ready-made one beyond recognition than to write from scratch. Thank you)
 
Newbie Spellweaver
Joined
Sep 1, 2021
Messages
10
Reaction score
0
Personally, I need to come up with a scheme to update Skyrim and MO2. The hash check is a great solution I think.
 
Upvote 0
cats addicted
Loyal Member
Joined
Apr 1, 2010
Messages
1,363
Reaction score
294
So you want a premade, that you can change to your needs ? Here you go:

Server:
Code:
public static class UpdaterConnector
    {
        private static Dictionary<string, string> hashes = new Dictionary<string, string>();
        private static int port = 44123;
        private static int tcpPort = 44321;

        public static void Start()
        {
            Console.Title = "Cat-X Updater Server";
            Console.BackgroundColor = ConsoleColor.DarkBlue;
            Console.ForegroundColor = ConsoleColor.Green;
            Console.Clear();

            Console.WriteLine("███████████████████████████");
            Console.WriteLine("█ Setting up directories: █");
            Console.WriteLine("███████████████████████████");
            Console.WriteLine("");
            Settings.workDir = Directory.GetCurrentDirectory();
            Console.WriteLine($"Working directory = {Settings.workDir}");
            Settings.clientDir = Path.Combine(Settings.workDir, "client");
            Console.WriteLine($"Client directory  = {Settings.clientDir}");
            Settings.hashFile = Path.Combine(Settings.workDir, "hashlist.dat");
            Console.WriteLine($"Hashlist File     = {Settings.hashFile}");
            Console.WriteLine("");
            Console.WriteLine("█████████████████████████");
            Console.WriteLine("█ Hashing client files: █");
            Console.WriteLine("█████████████████████████");
            HashClient();
            Console.WriteLine("█████████████████████████████████");
            Console.WriteLine("█ Waiting for incoming requests █");
            Console.WriteLine("█████████████████████████████████");
            Console.WriteLine("");
            Listener(port);
            Console.WriteLine("Up and running. For exit type quit. If you changed client files, type reload.");
            Console.WriteLine("");
            Commands("");
        }

        private static void HashClient()
        {
            hashes = new Dictionary<string, string>();
            Console.WriteLine("");
            Console.Write("Read in Client directory... ");
            string[] filesList = Directory.GetFiles(Settings.clientDir, "*.*", SearchOption.AllDirectories);
            Console.WriteLine($"{filesList.Length} files found.");
            Console.WriteLine($"Creating hash file list (could take a while)... ");
            if (File.Exists(Settings.hashFile)) { File.Delete(Settings.hashFile); }
            File.AppendAllText(Settings.hashFile, $"#################################{Environment.NewLine}");
            File.AppendAllText(Settings.hashFile, $"# Cat-X Update Server Hash List #{Environment.NewLine}");
            File.AppendAllText(Settings.hashFile, $"#################################{Environment.NewLine}");
            File.AppendAllText(Settings.hashFile, $"  {Environment.NewLine}");
            int i = 1;
            foreach (string  file in filesList)
            {
                string hash = GetMD5Checksum(file);
                string fileHelper = file.Replace(Settings.clientDir + "\\", "");
                string parser = $"{hash}|{fileHelper}{Environment.NewLine}";
                hashes.Add(fileHelper, hash);
                File.AppendAllText(Settings.hashFile, parser);
                Console.Write($"Written File {i}/{filesList.Length}\r");
                i++;
            }
            Console.WriteLine("");
            Console.WriteLine("done.");
            Console.WriteLine("");
        }

        public static string GetMD5Checksum(string filename)
        {
            using (var md5 = System.Security.Cryptography.MD5.Create())
            {
                using (var stream = System.IO.File.OpenRead(filename))
                {
                    var hash = md5.ComputeHash(stream);
                    return BitConverter.ToString(hash).Replace("-", "");
                }
            }
        }

        private static void ReloadHashes()
        {
            Console.Clear();
            Console.WriteLine("");
            Console.WriteLine("█████████████████████████");
            Console.WriteLine("█ Hashing client files: █");
            Console.WriteLine("█████████████████████████");
            Console.WriteLine("");
            HashClient();
            Console.WriteLine("████████████████████████████████████████████████");
            Console.WriteLine("█ Waiting for incoming requests on port {port} █");
            Console.WriteLine("████████████████████████████████████████████████");
            Console.WriteLine("");
            Console.WriteLine("Up and running. For exit type quit. If you changed client files, type reload.");
            Console.WriteLine("");
            Commands("");
        }

        private static void Commands(string command)
        {
            if(command.ToLower() != "quit")
            {
                if (command.ToLower() != "reload")
                {
                    string waiter = Console.ReadLine();
                    Commands(waiter);
                }
                ReloadHashes();
                return;
            }
            else
            {
                Environment.Exit(0);
            }
        }

        private static void DoExternalCommand(string data, string ip)
        {
            if (data.Contains("|"))
            {
                string[] d = data.Split('|');
                switch (d[0].ToLower())
                {
                    case "getlist":
                        SendFileToClient(Settings.hashFile, ip);
                        break;

                    case "downloadfile":
                        SendFileToClient(d[1], ip);
                        break;

                    default:
                        break;
                }
            }
        }

        private static bool CheckFile(string filename, string hash)
        {
            bool result = false;
            string parser = string.Empty;
            try { parser = hashes[filename]; }catch(Exception) { result = false; }
            if(hash == parser) { result = true; }
            return result;
        }

        private static void SendFileToClient(string file, string ip)
        {
            Console.WriteLine($"Sending {file} to {ip}.");
            string parser = Settings.clientDir + "\\" + file;
            new Thread(delegate () { SendFileToClient(parser, ip); }).Start();
        }

        public static void SendFileToClientTCP(string file, string ip)
        {
            Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipe = IPAddress.Parse(ip);
            client.Connect(ipe, tcpPort);
            Console.WriteLine($"Sending {file} to {ip}.");
            client.SendFile(file);
            client.Shutdown(SocketShutdown.Both);
            client.Close();
        }

        private static void Listener(int port)
        {
            new Thread(delegate () { Receiver(port); }).Start();
        }

        private static void ReceivedMessageParse(byte[] data, string ip)
        {
            string request = Encoding.ASCII.GetString(data);
            DoExternalCommand(request, ip);
        }

        public static void Receiver(int port)
        {

            UdpClient Udpclient = new UdpClient(port);
            IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
            try
            {
                byte[] receiveBytes = Udpclient.Receive(ref RemoteIpEndPoint);
                UpdaterConnector.ReceivedMessageParse(receiveBytes, RemoteIpEndPoint.ToString());
                Udpclient.Close();
                UpdaterConnector.Listener(port);
            }
            catch (Exception)
            {
                Udpclient.Close();
                UpdaterConnector.Listener(port);
            }
        }

        private static void SendData(string data, string ip)
        {
            byte[] parser = Encoding.ASCII.GetBytes(data);
            Send(ip, parser);
        }

        public static void Send(string ip, byte[] data)
        {
            new Thread(delegate () { UdpSend(port, data, ip); }).Start();
        }

        private static void UdpSend(int port, byte[] data, string serveradress)
        {
            UdpClient udpClient = new UdpClient(serveradress, port);
            try
            {
                udpClient.Send(data, data.Length);
                udpClient.Close();
            }
            catch (Exception)
            {
                udpClient.Close();
            }
        }
    }

All you have to do is create a simple client, that gets the hash list, than compare it to the hash of the local files and request diffrent files from server. That simple. For checking the hash you can just grab the part from server to create a hashlist, then compare them in a foreach loop.

(The Settings.xxx in server is just a public static class named Settings with workdir , clientdir and hashfile as static strings. Nothing more.)
 
Upvote 0
Back
Top