Topic: CentrEd Profile

/***************************************************************************
 *            QServer (UO: Quintessense)         Created by :        StaticZ
 *                                               url : http://dev.uoquint.ru
 *    file: CentrEd.cs (2010.08.11)              email :  staticz@uoquint.ru
 ***************************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace Server.Misc.CentrEd
{
    // NOTE: Maps are defined in Map enum (name of map not important and map value equel to left shift for 0x01 multiplyed 
    // by map order number), if config#.xml not found for map, it will be ignored. Other values can be used for easy working, 
    // like Map.Everyone as combination of Adefined maps. Everyone value must by equel for combination of all possible values.

    [Flags]
    public enum Map : byte
    {
        Dangeon  = 0x01,    // Map#0
        Sosaria  = 0x02,    // Map#1
        Unused2  = 0x04,    // Map#2
        Unused3  = 0x08,    // Map#3
        Unused4  = 0x10,    // Map#4
        Unused5  = 0x20,    // Map#5
        Unused6  = 0x40,    // Map#6
        Unused7  = 0x80,    // Map#7
        Everyone = Dangeon | Sosaria
    }

    public static class CedServer
    {
        private static int[] GetMapIndex(Map map)
        {
            var index = new List<int>(8);
            if (((int)map & 0x01) == 0x01) index.Add(0);
            if (((int)map & 0x02) == 0x02) index.Add(1);
            if (((int)map & 0x04) == 0x04) index.Add(2);
            if (((int)map & 0x08) == 0x08) index.Add(3);
            if (((int)map & 0x10) == 0x10) index.Add(4);
            if (((int)map & 0x20) == 0x20) index.Add(5);
            if (((int)map & 0x40) == 0x40) index.Add(6);
            if (((int)map & 0x80) == 0x80) index.Add(7);
            return index.ToArray();
        }

        [CallPriority(10)]
        public static void Configure()
        {
            process = new Process[8];
            Array.Clear(process, 0, process.Length);

            EventSink.Crashed  += new CrashedEventHandler(Crashed);
            EventSink.Shutdown += new ShutdownEventHandler(Shutdown);
 
            // To speedup loading on localhost let's skip there starting.
            if (!Core.Localhost) {
                KillAll();
                Run(Map.Everyone);
            }
        }

        private static Process[] process = null;

        public static bool IsRuning(Map map) 
        {
            bool result = true;
            foreach (var i in GetMapIndex(map)) {
                if (process[i] == null)
                    result = false;
            }
            return result;
        }

        public static long GetTotalMemory()
        {
            long memmory = 0;
            foreach(Process p in process)
                if (p != null)
                    memmory += p.WorkingSet64;
            return memmory;
        }

        public static void Run(Map map)
        {
            if (Working) {
                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr#", ConsoleColor.White, " Can't lunch cedserv until file copying operation willn't finished.");
                return;
            }

            string directory = Path.Combine(Core.BaseDirectory, @"data\cedserv");
            foreach (var i in GetMapIndex(map)){
                if (process[i] != null || !File.Exists(Path.Combine(Core.BaseDirectory, String.Format(@"data\cedserv\config-map{0}.xml", i))))
                    continue;

                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), ConsoleColor.White, 
                                         String.Format("Lunch cedserv for facet - {0}...", Enum.GetName(typeof(Map), 0x01 << i)));
                process[i] = new Process();
                process[i].StartInfo.FileName = Path.Combine(Path.GetDirectoryName(Core.ExePath), @"cedserver.exe");
                process[i].StartInfo.Arguments = String.Format(@".\..\data\cedserv\config-map{0}.xml", i);
                process[i].StartInfo.UseShellExecute = false;
                process[i].StartInfo.CreateNoWindow = false;
                process[i].StartInfo.RedirectStandardOutput = true;
                process[i].StartInfo.StandardOutputEncoding = Encoding.GetEncoding(866); //1251
                process[i].OutputDataReceived += new DataReceivedEventHandler(ConsoleOutputHandler);
                process[i].EnableRaisingEvents = true;
                process[i].Exited += new EventHandler(ExitProcessHandler);

                process[i].Start();
                process[i].BeginOutputReadLine();
            }
        }

        #region WinApiExport 
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        private static readonly uint WM_DESTROY = 0x0002;
        private static readonly uint WM_CLOSE   = 0x0010;
        private static readonly uint WM_QUIT    = 0x0012;
        
        private static void PostMessageSafe(HandleRef hWnd, uint msg, IntPtr wParam, IntPtr lParam)
        {
            bool returnValue = PostMessage(hWnd, msg, wParam, lParam);
            if (!returnValue)
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        #endregion

        public static void Close(Map map)
        {
            foreach (var i in GetMapIndex(map)) {
                if (process[i] != null) {
                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), ConsoleColor.White,
                                             String.Format("Shutdown cedserv process for facet - {0}...", Enum.GetName(typeof(Map), 0x01 << i)));
                    bool result = PostMessage(new HandleRef(process[i], process[i].Handle), WM_QUIT, IntPtr.Zero, IntPtr.Zero);

                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), ConsoleColor.White, "Waiting for precess shutdown.....");
                    if (process[i].WaitForExit(30000)) {
                        if (result) {
                            Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), ConsoleColor.White, "Process was shutdown");
                        } else {
                            int error = Marshal.GetLastWin32Error();
                            string errormsg = error.ToString();
                            if (error == 1400)
                                errormsg += " (Invalid window handle.)";

                            Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), ConsoleColor.White, "Process shutdowned with error: " + errormsg);
                        }
                        result = true;
                    } else {
                        Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), ConsoleColor.White, "Timeout left.");
                        result = false;
                    }

                    if (result)
                        process[i] = null;
                }
            }
        }

        public static void Kill(Map map)
        {
            foreach (var i in GetMapIndex(map)) {
                if (process[i] != null) {
                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), ConsoleColor.White,
                                             String.Format("Terminating cedserv process for facet - {0}", Enum.GetName(typeof(Map), 0x01 << i)));
                    try {
                        process[i].Kill();
                        process[i] = null;
                        Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), ConsoleColor.White, "Process was terminated.");
                    } catch (Exception) {
                        Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), ConsoleColor.White, "Exception was thrown while process terminating.");
                    } finally {

                    }
                }
            }
        }

        public static void KillAll()
        {
            Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr#", ConsoleColor.White, " Terminating all cedserver processes");
            try {
                Process[] m_processes = Process.GetProcessesByName("cedserver");
                foreach (Process m_process in m_processes) {
                    string desc = String.Format("PID: {0}\tЗапущен: {1}", m_process.Id, m_process.StartTime);
                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr#", ConsoleColor.White, " Found process - " + desc + "\tterminating...");
                    m_process.Kill();
                }

                Array.Clear(process, 0, process.Length);
                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr#", ConsoleColor.White, " All processes where sucsessfully terminated.");
            } catch (Exception) {
                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr#", ConsoleColor.White, " Exception was thrown while processes terminating.");
            } finally {

            }
        }

        private static void ConsoleOutputHandler(object sendingProcess, DataReceivedEventArgs recieved)
        {
            if (!String.IsNullOrEmpty(recieved.Data)) {
                if(recieved.Data.StartsWith("Copyright"))
                    return;
 
                string recieveddata;
                if (recieved.Data.Contains("Get error")) {
                    int indexof  = recieved.Data.IndexOf("Get error");
                    recieveddata = recieved.Data.Substring(0, indexof);
                    string error = recieved.Data.Substring(indexof);
                    byte[] bytes = Encoding.GetEncoding(866).GetBytes(error);
                    error = Encoding.GetEncoding(1251).GetString(bytes);
                    recieveddata += error;
                } else
                    recieveddata = recieved.Data;

                for (int i = 0; i < process.Length; ++i)
                    if (sendingProcess == process[i]) {
                        Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), 
                                                 ConsoleColor.White, recieveddata);
                        return;
                    }
                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr_UnknownProcess", ConsoleColor.White, recieveddata);
            }
        }

        private static void ExitProcessHandler(object sendingProcess, EventArgs e)
        {
            for (int i = 0; i < process.Length; ++i)
                if (sendingProcess == process[i]) {
                    process[i] = null;
                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, String.Format("Centr{0}", i), 
                                             ConsoleColor.White, "Process sucsessfully shutdown itself.");
                    return;
                }
            Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr_UnknownProcess", ConsoleColor.White, "Process sucsessfully shutdown itself.");
        }

        private static void Shutdown(ShutdownEventArgs e)
        {
            Close(Map.Everyone);
            if (Core.Localhost)
                Kill(Map.Everyone);
            else
                KillAll();
        }

        private static void Crashed(CrashedEventArgs e)
        {
            #if DEBUG
            Kill(Map.Everyone);
            #else
            KillAll();
            #endif
        }

        public static void CopyMapToRunUo(Map map)
        {
            if (Working) {
                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr#", ConsoleColor.White, 
                    " Copying operation can't be executed as at this moment already is lunched another copying operation. Please wait until it finished and repeat action.");
                return;
            }
            Working = true;
            bool m_Idle = true;

            string m_centr = String.Empty;
            string m_souceFileName = String.Empty;
            string m_destFileName = String.Empty;

            foreach (var i in GetMapIndex(map)) {
                m_centr = String.Format("Centr{0}", i);
                if (process[i] == null) {
                    m_Idle = false;
                    m_souceFileName = Path.Combine(Core.BaseDirectory, String.Format(@"data\cedserv\map{0}.mul", i));
                    m_destFileName  = Path.Combine(Core.BaseDirectory, String.Format(@"data\map{0}.mul", i));

                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, String.Format("Copying map{0}.mul from \"cedserv\\..\" to \"runuo\\..\"", i));

                    Thread workThread = new Thread(CedServer.FileCopyThread);
                    workThread.Priority = ThreadPriority.Lowest;
                    workThread.Start(new string[] { m_centr, m_souceFileName, m_destFileName });
                } else
                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, "For files copying CentrED server must be turned of first.");
            }

            if (m_Idle)
                Working = false;
        }

        public static void CopyMapFromRunUo(Map map)
        {
            if (Working) {
                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr#", ConsoleColor.White, 
                                         " Copying operation can't be executed as at this moment already is lunched another copying operation. Please wait until it finished and repeat action.");
                return;
            }
            Working = true;
            bool m_Idle = true;

            string m_centr = String.Empty;
            string m_souceFileName = String.Empty;
            string m_destFileName = String.Empty;

            foreach (var i in GetMapIndex(map)) {
                m_centr = String.Format("Centr{0}", i);
                if (process[i] == null) {
                    m_Idle = false;
                    m_souceFileName = Path.Combine(Core.BaseDirectory, String.Format(@"data\map{0}.mul", i));
                    m_destFileName  = Path.Combine(Core.BaseDirectory, String.Format(@"data\cedserv\map{0}.mul", i));

                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, String.Format("Copying map{0}.mul from \"runuo\\..\" to \"cedserv\\..\"", i));

                    Thread workThread = new Thread(CedServer.FileCopyThread);
                    workThread.Priority = ThreadPriority.Lowest;
                    workThread.Start(new string[] { m_centr, m_souceFileName, m_destFileName });
                } else
                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, "For files copying CentrED server must be turned of first.");
            }

            if (m_Idle)
                Working = false;
        }

        public static void CopyStaticsToRunUo(Map map)
        {
            if (Working) {
                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr#", ConsoleColor.White, 
                                         " Copying operation can't be executed as at this moment already is lunched another copying operation. Please wait until it finished and repeat action.");
                return;
            }
            Working = true;
            bool m_Idle = true;

            string m_centr = String.Empty;
            string m_souceFileName = String.Empty;
            string m_destFileName = String.Empty;

            foreach (var i in GetMapIndex(map)) {
                m_centr = String.Format("Centr{0}", i);
                if (process[i] == null) {
                    m_Idle = false;
                    m_souceFileName = Path.Combine(Core.BaseDirectory, String.Format(@"data\cedserv\statics{0}.mul", i));
                    m_destFileName  = Path.Combine(Core.BaseDirectory, String.Format(@"data\statics{0}.mul", i));

                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, String.Format("Copying statics{0}.mul from \"cedserv\\..\" to \"runuo\\..\"", i));

                    Thread workThread1 = new Thread(CedServer.FileCopyThread);
                    workThread1.Priority = ThreadPriority.Lowest;
                    workThread1.Start(new string[] { m_centr, m_souceFileName, m_destFileName });


                    m_souceFileName = Path.Combine(Core.BaseDirectory, String.Format(@"data\cedserv\staidx{0}.mul", i));
                    m_destFileName  = Path.Combine(Core.BaseDirectory, String.Format(@"data\staidx{0}.mul", i));

                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, String.Format("Copying staidx{0}.mul from \"cedserv\\..\" to \"runuo\\..\"", i));

                    Thread workThread2 = new Thread(CedServer.FileCopyThread);
                    workThread2.Priority = ThreadPriority.Lowest;
                    workThread2.Start(new string[] { m_centr, m_souceFileName, m_destFileName });
                } else
                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, "For files copying CentrED server must be turned of first.");
            }
            if (m_Idle)
                Working = false;
        }

        public static void CopyStaticsFromRunUo(Map map)
        {
            if (Working) {
                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr#", ConsoleColor.White,
                                         " Copying operation can't be executed as at this moment already is lunched another copying operation. Please wait until it finished and repeat action.");
                return;
            }
            Working = true;
            bool m_Idle = true;

            string m_centr = String.Empty;
            string m_souceFileName = String.Empty;
            string m_destFileName = String.Empty;

            foreach (var i in GetMapIndex(map)) {
                m_centr = String.Format("Centr{0}", i);
                if (process[i] == null) {
                    m_Idle = false;
                    m_souceFileName = Path.Combine(Core.BaseDirectory, String.Format(@"data\statics{0}.mul", i));
                    m_destFileName  = Path.Combine(Core.BaseDirectory, String.Format(@"data\cedserv\statics{0}.mul", i));

                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, String.Format("Копируется statics{0}.mul from \"cedserv\\..\" to \"runuo\\..\"", i));

                    Thread workThread1 = new Thread(CedServer.FileCopyThread);
                    workThread1.Priority = ThreadPriority.Lowest;
                    workThread1.Start(new string[] { m_centr, m_souceFileName, m_destFileName });


                    m_souceFileName = Path.Combine(Core.BaseDirectory, String.Format(@"data\staidx{0}.mul", i));
                    m_destFileName  = Path.Combine(Core.BaseDirectory, String.Format(@"data\cedserv\staidx{0}.mul", i));

                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, String.Format("Копируется staidx{0}.mul from \"cedserv\\..\" to \"runuo\\..\"", i));

                    Thread workThread2 = new Thread(CedServer.FileCopyThread);
                    workThread2.Priority = ThreadPriority.Lowest;
                    workThread2.Start(new string[] { m_centr, m_souceFileName, m_destFileName });
                } else
                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, "For files copying CentrED server must be turned of first.");
            }
            if (m_Idle)
                Working = false;
        }

        /// <summary>
        /// Checking if in that moment cedserver files are copying
        /// </summary>
        private static bool Working
        { 
            get 
            {
                if (m_Working && DateTime.Now.Subtract(m_LastWork).CompareTo(m_TimeOut) >= 0)
                {
                    Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, "Centr#", ConsoleColor.DarkRed, 
                        "Copying operation is working more then {0} minutes or error while copying had occured. Flag Server.Misc.CedServer.Working was force changed to \"false\" value", 
                        (int)m_TimeOut.TotalMinutes);
                    m_Working = false;
                }
                return m_Working; 
            }
            set 
            {
                if (m_Working == value)
                    return;

                m_Working = value;
                if (m_Working)
                    m_LastWork = DateTime.Now;
            }
        }
        private static bool m_Working = false;
        private static DateTime m_LastWork = DateTime.MinValue;
        private static TimeSpan m_TimeOut = TimeSpan.FromMinutes(10.0);

        private static void FileCopyThread(Object data)
        {
            string[] m_Data = data as string[];
            string m_centr = m_Data[0];
            string m_souceFileName = m_Data[1];
            string m_destFileName  = m_Data[2]; 

            try {
                File.Copy(m_souceFileName, m_destFileName, true);
                string m_FileName = Path.GetFileName(m_souceFileName);
                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, "Copying file \"{0}\" finished.", m_FileName);
            } catch (Exception e) {
                Utility.ConsoleWriteLine(ConsoleColor.DarkMagenta, m_centr, ConsoleColor.White, e.Message);
            }

            Working = false;
        }

    }
}
Game isn't a dream, it is the reality, reality which is coming while we dream...

Re: CentrEd Profile

Wow. This amazing. I can't wait to check this out.

Re: CentrEd Profile

If there are any problems - write, I made all this to ower own server (fork based on RunUO 2.0 were lot of code was rewrited), not as separated systems. Thow it must work with all version, but I don't check it myself and may skiped something.. Especialy if you are using mono as I don't care about supporting linux and\or mono at all....

And one more - if you get problems with text, replace encoding to yours. As here all used russian encodings (1251 for windows and 866 for dos), thow for english this can't cause problems but with others languages can.

Game isn't a dream, it is the reality, reality which is coming while we dream...