Register for your free account! | Forgot your password?

Go Back   elitepvpers > MMORPGs > Conquer Online 2 > CO2 Private Server > CO2 PServer Guides & Releases
You last visited: Today at 11:23

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



[Updated Guide] How to Create a Graphical User Interface (GUI) With Console

Discussion on [Updated Guide] How to Create a Graphical User Interface (GUI) With Console within the CO2 PServer Guides & Releases forum part of the CO2 Private Server category.

Reply
 
Old   #1
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,283
Received Thanks: 4,192
[Updated Guide] How to Create a Graphical User Interface (GUI) With Console

Introduction:
Hey everyone. I was requested to remake this guide, so I am. It's a lot to rewrite, so don't expect perfect grammar and spelling (I don't have the time to check). Also, I'm not saying that this is the most efficient way of doing things - I'm just showing you how I do it for my server. I'm also assuming that you're working on a Conquer Online server, but remember that this can be applied to any C# application, really.

Creating the Graphical User Interface:
  1. I'm going to be using an example project for this guide. As I said, you can use any project. If your project isn't a Windows Application (it's a Console Application), then you'll have to change that. To do that, right click on your project and select "Properties" (or select it and press Alt+Enter).



    In the properties window, on the Application tab (default if you've never opened properties before), you'll see "Output Type". Change that to "Windows Application".



  2. Cool. So let's make the graphical user interface (GUI) now. The technology I'll be using in this tutorial is Windows Forms. It's all we need for something like this that has no need for heavy graphical updates (what we're trying to avoid with a server application). I don't care where you put your form, but you're going to right click on your project again and this time select "Add" and "New item" (from the submenu).



    Feel free to name this whatever you want. I called mine "Server.cs" for this example. Remember to keep the ".cs" at the end of the name (it's the file extension for C-Sharp). All references needed to run the GUI will be added to your project automatically.

  3. Alright. So now you have a little GUI to play around with. Let's customize a few things before we get started. To customize the GUI, right click on it and select "Properties". It'll bring up the side bar that you see below.



    Changing the text will change the name of the window upon start up. You can also set the icon for the task bar using the Properties window.

  4. Now we need to add the GUI to the program. We can to do this in the main function (the entry point for the program). It's important that we do not put the GUI on the main thread (because we want to run the server on the main thread). In this example, I'll be creating the GUI on its own thread. To do this, you'll have to import the following namespaces like so:

    Code:
    using System.Threading;
    using System.Windows.Forms;
    After adding the namespaces, you'll start a new thread to run the server. You can do this in an anonymous inner function (shown below). You can also create a separate function if you wish (this is a bit more compact though).
    Code:
    [MTAThread]
    static void Main(string[] args)
    {
    Server server = new Server();
    new Thread(() => 
    {
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(fals e);
    Application.Run(server);
    
    }) { Priority = ThreadPriority.Lowest }.Start();
    }
    You'll also have to add the "[MTAThread]" attribute to your main function so the server loads on a multi-threaded apartment level main thread. This is very important towards the performance of your server.

  5. Now if you run your project, you'll see the GUI pop up (as shown below). Unfortunately, the close option will not always work (because your server will hopefully make use of multithreading). We'll have to make a close action to terminate the server upon close.



    To create a new event that closes the server when the form closes, go back to your GUI properties window and click on the lightning bolt icon. To the right of "FormClosed", double click and it will create a new event automatically for you.



    Then you'll want to terminate the server (using "System.Environment.Exit" as shown below).

    Code:
    private void Server_FormClosed(object sender, FormClosedEventArgs e)
    {
    // TODO: Whatever Logic you want to do before the server terminates.
    Environment.Exit(0);
    }
Preparing Output in the Graphical User Interface:
  1. Great, so now we both have a running example of a GUI. Our goal is to create a console inside of the GUI. First, we need to prepare the GUI so it's capable of accepting text from the other threads (without the use of cross-threading since Windows Forms are not thread safe). First, let's create a Text Box. To do that, you'll need to open the Toolbox window (Ctrl + Alt + X). Select the "TextBox" item and make the output box in the GUI. This is going to be out console.



    Now click on the textbox and select "Properties". From the properties window, select Multiline and change that to "True" (as shown above). You can also change the colors of the window here. I also recommend you change the "Readonly" to true (if you don't want people writing to the console). If you do that, you'll have to change the backcolor back to "Window". In that window, you'll also want to change it's name to "consoleTextBox".

  2. With the textbox in place, it's now time to add support methods for writing to it. We're going to do this by creating a delegate method declaration and definition. I created a class for my that will do this for you. Below is that class (change the namespace to fit wherever you're putting it).

    Code:
    // Created by Spirited Fang for the Burning Skies project.
    // Released for public use.
    namespace Kibou.OutputManagement
    {
    using System.Windows.Forms;
    using System.IO;
    
    // Delegate Function Declarations:
    /// <summary>
    /// This method appends a line to the application's text box. If the text being passed is empty, it will not 
    /// execute and return to the parent function / method. If there is no room for the new line in the text box,
    /// the text box will be cut to make room.
    /// </summary>
    /// <param name="line">The line being appended to the text box.</param>
    public delegate void LineWriter(string line);
    
    /// <summary>
    /// This class creates a new implementation of the abstract string text stream class to redirect an output stream
    /// to a text box. It accepts a text box from the active application and is programmed to override the Console 
    /// class defined by System in the .NET Framework.
    /// </summary>
    public sealed class ConsoleRedirect : TextWriter
    {
    // Class Scope Variable Declarations:
    private TextBox _outputTextBox; // This text box is where the output will be redirected to.
    private LineWriter _writer; // Controls all appending lines to the text box console. 
    
    // Constructor:
    /// <summary>
    /// This class creates a new implementation of the abstract string text stream class to redirect an output 
    /// stream to a text box. It accepts a text box from the active application and is programmed to override the 
    /// Console class defined by System in the .NET Framework.
    /// </summary>
    /// <param name="textBox">Where the output will be redirected to.</param>
    /// <param name="writer">Controls all appending lines to the text box console.</param>
    public ConsoleRedirect(TextBox textBox, LineWriter writer)
    {
    // Set the output textbox.
    _outputTextBox = textBox;
    _writer = writer;
    }
    
    /// <summary>
    /// This method appends a line to the application's text box. If the text being passed is empty, it will not 
    /// execute and return to the parent function / method. If there is no room for the new line in the text box,
    /// the text box will be cut to make room.
    /// </summary>
    /// <param name="line">The line being appended to the text box.</param>
    public void AppendLine(string line)
    {
    try
    {
    // Error check the string contents & text box, then invoke the append line method:
    if (line != string.Empty && _outputTextBox != null)
    _outputTextBox.BeginInvoke(_writer, line);
    }
    catch (System.Exception e)
    {
    // If the text box isn't null, try to display an error:
    if (_outputTextBox != null && _outputTextBox.Created && !_outputTextBox.Disposing)
    _outputTextBox.BeginInvoke(_writer, e);
    }
    }
    
    #region Property Overrides
    // Encoding and Format Overrides:
    public override System.Text.Encoding Encoding
    {
    get { return System.Text.Encoding.UTF8; }
    }
    public override System.IFormatProvider FormatProvider
    {
    get
    {
    return System.Threading.Thread.CurrentThread.CurrentCultu re;
    }
    }
    public override string NewLine
    {
    get
    {
    return "\r\n";
    }
    set
    {
    throw new System.NotImplementedException();
    }
    }
    #endregion
    
    #region Method Overrides
    // Write Overrides:
    public override void Write(bool value)
    {
    AppendLine(value.ToString());
    }
    public override void Write(char value)
    {
    AppendLine(value.ToString());
    }
    public override void Write(char[] buffer)
    {
    string value = "";
    foreach (var character in buffer)
    value += character.ToString() + " ";
    AppendLine(value);
    }
    public override void Write(char[] buffer, int index, int count)
    {
    string value = "";
    for (; index < index + count; index++)
    value += buffer[index].ToString() + " ";
    AppendLine(value);
    }
    public override void Write(decimal value)
    {
    AppendLine(value.ToString());
    }
    public override void Write(double value)
    {
    AppendLine(value.ToString());
    }
    public override void Write(float value)
    {
    AppendLine(value.ToString());
    }
    public override void Write(int value)
    {
    AppendLine(value.ToString());
    }
    public override void Write(long value)
    {
    AppendLine(value.ToString());
    }
    public override void Write(object value)
    {
    AppendLine(value.ToString());
    }
    public override void Write(string format, object arg0)
    {
    AppendLine(string.Format(this.FormatProvider, format, new object[] { arg0 })
    .Replace("\n", NewLine));
    }
    public override void Write(string format, object arg0, object arg1)
    {
    AppendLine(string.Format(this.FormatProvider, format, new object[] { arg0, arg1 })
    .Replace("\n", NewLine));
    }
    public override void Write(string format, object arg0, object arg1, object arg2)
    {
    AppendLine(string.Format(this.FormatProvider, format, new object[] { arg0, arg1, arg2 })
    .Replace("\n", NewLine));
    }
    public override void Write(string format, params object[] arg)
    {
    if (arg != null)
    AppendLine(string.Format(this.FormatProvider, format, arg)
    .Replace("\n", NewLine));
    else
    AppendLine(string.Format(this.FormatProvider, format, null)
    .Replace("\n", NewLine));
    }
    public override void Write(string value)
    {
    AppendLine(value.Replace("\n", NewLine));
    }
    public override void Write(uint value)
    {
    AppendLine(value.ToString());
    }
    public override void Write(ulong value)
    {
    AppendLine(value.ToString());
    }
    
    // Write Line Overrides:
    public override void WriteLine()
    {
    AppendLine(NewLine);
    }
    public override void WriteLine(bool value)
    {
    AppendLine(value.ToString() + NewLine);
    }
    public override void WriteLine(char value)
    {
    AppendLine(value.ToString() + NewLine);
    }
    public override void WriteLine(char[] buffer)
    {
    string value = "";
    foreach (var character in buffer)
    value += character.ToString() + " ";
    AppendLine(value + NewLine);
    }
    public override void WriteLine(char[] buffer, int index, int count)
    {
    string value = "";
    for (; index < index + count; index++)
    value += buffer[index].ToString() + " ";
    AppendLine(value + NewLine);
    }
    public override void WriteLine(decimal value)
    {
    AppendLine(value.ToString() + NewLine);
    }
    public override void WriteLine(double value)
    {
    AppendLine(value.ToString() + NewLine);
    }
    public override void WriteLine(float value)
    {
    AppendLine(value.ToString() + NewLine);
    }
    public override void WriteLine(int value)
    {
    AppendLine(value.ToString() + NewLine);
    }
    public override void WriteLine(long value)
    {
    AppendLine(value.ToString() + NewLine);
    }
    public override void WriteLine(object value)
    {
    AppendLine(value.ToString() + NewLine);
    }
    public override void WriteLine(string format, object arg0)
    {
    AppendLine(string.Format(this.FormatProvider, format, new object[] { arg0 })
    .Replace("\n", NewLine) + NewLine);
    }
    public override void WriteLine(string format, object arg0, object arg1)
    {
    AppendLine(string.Format(this.FormatProvider, format, new object[] { arg0, arg1 })
    .Replace("\n", NewLine) + NewLine);
    }
    public override void WriteLine(string format, object arg0, object arg1, object arg2)
    {
    AppendLine(string.Format(this.FormatProvider, format, new object[] { arg0, arg1, arg2 })
    .Replace("\n", NewLine) + NewLine);
    }
    public override void WriteLine(string format, params object[] arg)
    {
    if (arg != null)
    AppendLine(string.Format(this.FormatProvider, format, arg)
    .Replace("\n", NewLine) + NewLine);
    else
    AppendLine(string.Format(this.FormatProvider, format, null)
    .Replace("\n", NewLine) + NewLine);
    }
    public override void WriteLine(string value)
    {
    AppendLine(value.Replace("\n", NewLine) + NewLine);
    }
    public override void WriteLine(uint value)
    {
    AppendLine(value.ToString() + NewLine);
    }
    public override void WriteLine(ulong value)
    {
    AppendLine(value.ToString() + NewLine);
    }
    #endregion
    }
    }
  3. With that code, you'll be able to redirect all output in your project. You'll be initializing it in your GUI's constructor, but first we need to add the append line method. Right click on your GUI and select "View Code". Then, add the following code to your class:

    Code:
    /// <summary>
    /// This method appends a line to the application's text box. If the text being passed is empty, it will not 
    /// execute and return to the parent function / method. If there is no room for the new line in the text box,
    /// the text box will be cut to make room.
    /// </summary>
    /// <param name="line">The line being appended to the text box.</param>
    public void AppendLine(string line)
    {
    // Since the text box only has room for a certain amount of characters, we must make room for the new line:
    while (consoleTextBox.Text.Length + line.Length > consoleTextBox.MaxLength)
    consoleTextBox.Text = consoleTextBox.Text.Remove(0, consoleTextBox.Text.IndexOf(Console.Out.NewLine) + 2);
    
    // Append the new line:
    consoleTextBox.AppendText(line);
    }
    The word wrapping is a bit inefficient for servers, so try to avoid having to use it too much. It's only there for protection (you shouldn't have to use it if you're doing normal amounts of text).

  4. With the append line method finished, we're now going to add the console redirect to the form's constructor. Here's an example showing that:

    Code:
    public Server()
    {
    InitializeComponent();
    Console.SetOut(new ConsoleRedirect(consoleTextBox, new LineWriter(AppendLine)));
    }
  5. Take note that you will not be able to use the console output until the GUI window is created (don't worry, it won't crash using the class I provided you with). We can tell the server to wait though until the server's GUI has completed loading (the constructor has been run). You do that by writing the following loop (below). Feel free to add that to the main function after the thread start.

    Code:
    while (!server.Created) Thread.Sleep(100);
    That that will do is check the GUI every 100 milliseconds to see if it's created. If it hasn't been created, it will keep waiting. After doing that, you should have a working console in your GUI (that doesn't rely on print timers)!
Switching Between Console & Application Mode:
  1. Now, this is all great, and you're done and all, but servers really shouldn't have a GUI. They're programmed for efficiency, not consumer usability (unless you're releasing the server as a consumer product, of course). Even servers like Minecraft have a switch though that allows it to run as a console program. Let's make that switch using command line arguments (this is completely optional).

    Code:
    // Check if the user wants to start the program in console mode:
    Boolean consoleMode;
    if (args.Length > 0 && Boolean.TryParse(args[0], out consoleMode))
    {
    
    }
    The above code is going to be true when the command line argument is "true". This is how the user is going to run the server as a console program.

  2. Now we need to create a console window for the server. You can do this using a class I created (again) for my . The class allocates memory and creates a new console for the server (unless the program is being created in a console window already, in which case it will attach to that process). Again, you will change the namespace to your default namespace.

    Code:
    // Created by Spirited Fang for the Burning Skies project.
    // Released for public use.
    namespace Kibou.OutputManagement
    {
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    /// <summary>
    /// This class encapsulates a function that creates a new console window in a Windows Application project. The
    /// servers use this function to open a new command window (if the command line arguments at index one is set to 
    /// "true").
    /// </summary>
    public static class ConsoleCreation
    {
    /// <summary> Allocates a new console for the calling process. </summary>
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool AllocConsole();
    
    /// <summary> Detaches the calling process from its console. </summary>
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool FreeConsole();
    
    /// <summary> Attaches the calling process to the console of the specified process. </summary>
    /// <param name="dwProcessId">The identifier of the process whose console is to be used.</param>
    [DllImport("kernel32", SetLastError = true)]
    static extern bool AttachConsole(int dwProcessId);
    
    /// <summary>
    /// Retrieves a handle to the foreground window (the window with which the user is currently working). 
    /// The system assigns a slightly higher priority to the thread that creates the foreground window than 
    /// it does to other threads. 
    /// </summary>
    [DllImport("user32.dll")]
    static extern IntPtr GetForegroundWindow();
    
    /// <summary>
    /// Retrieves the identifier of the thread that created the specified window and, optionally, the identifier
    /// of the process that created the window. 
    /// </summary>
    /// <param name="hWnd">A handle to the window. </param>
    /// <param name="lpdwProcessId">A pointer to a variable that receives the process identifier.</param>
    [DllImport("user32.dll", SetLastError = true)]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
    
    /// <summary>
    /// This function creates a new console command window using invoke methods from Window's standard libraries.
    /// If the window already exists (the program is being run from the command prompt), this function will attach
    /// the program to it. It returns true if the console is being created.
    /// </summary>
    public static void Handle()
    {
    // Get the process of the uppermost window (taking that that's the shell calling it, if it exists). If it
    // exists, and the process name is "cmd", then attach to that console window.
    IntPtr ptr = GetForegroundWindow();
    int processId;
    GetWindowThreadProcessId(ptr, out processId);
    Process process = Process.GetProcessById(processId);
    
    // If the process exists, and the process name is "cmd", then attach to that console window.
    if (process != null && process.ProcessName == "cmd")
    AttachConsole(processId);
    else // There is no console. Let's allocate memory for a new one and run it:
    AllocConsole();
    }
    
    /// <summary> This function frees the console allocated by the program. </summary>
    public static void Free()
    {
    FreeConsole();
    }
    }
    }
  3. All you have to do now is implement the class similarly to how I implemented it below. You can also put your server logic in a new function so you don't have to duplicate anything (I highly suggest you do that since that's one of the main points of using an object oriented language).
    Code:
    [MTAThread]
    static void Main(string[] args)
    {
    // Check if the user wants to start the program in console mode:
    Boolean consoleMode;
    if (args.Length > 0 && Boolean.TryParse(args[0], out consoleMode) && consoleMode)
    {
    ConsoleCreation.Handle();
    Console.Title = "Example";
    StartServer();
    ConsoleCreation.Free(); // Frees the console when the application is closing.
    }
    else
    {
    // Create the GUI:
    Server server = new Server();
    new Thread(() =>
    {
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(fals e);
    Application.Run(server);
    
    }) { Priority = ThreadPriority.Lowest }.Start();
    
    while (!server.Created) Thread.Sleep(100);
    StartServer();
    }
    }
    
    static void StartServer()
    {
    // TODO: Server Logic
    }
  4. Now it's time to test it. You can test it by opening your project's properties again and going to the "Debug" tab. In that tab, you have "Command line arguments" under "Start Options". Put "true" there and you'll be able to test console mode.


Creating Menus for Commands:
  1. This is another optional group of instructions for if you have command line server commands and want to implement them into your GUI. There are many ways you can do this, but the cleanest way would be to create a menu. Reopen your GUI and the toolbox (Ctrl + Alt + X) and double click on "MenuStrip".



    For my example, I chose "System" for my render mode (click the arrow in the top right corner after selecting it). I chose that because we want to minimize rendering.

  2. Alright. Now type something in the "Type Here" field. I'm going to type "File" in as the name for my example menu. From there, you'll get a quick feel for the process of creating menu items and submenus. Now, when you click on a menu item, it's supposed to perform an action (which we'll need to define). Doing so is quite easy, just double click on the menu item that you want to create an action for (and it will be created automatically). In my example, I'm creating a "Clear Console" command.

    Code:
    private void clearConsoleToolStripMenuItem_Click(object sender, EventArgs e)
    {
    consoleTextBox.Clear();
    }


  3. Cool. Now let's create a command that will kill all open clients (since they tend to crash a lot when updating packets and such). I created this menu to hold it (below). Now, the process of killing all clients is quite simple. For each process running, if the process is "Conquer", kill the process. Below is also my code from my Burning Skies project for killing processes.



    Code:
    /// <summary> This method kills all open clients. </summary>
    private void killAllClientsToolStripMenuItem_Click(object sender, EventArgs e)
    {
    Console.WriteLine("Killing clients...");
    Process[] processes = Process.GetProcessesByName("Conquer");
    
    foreach (Process client in processes)
    if (client.ProcessName.Length == "Conquer".Length)
    try { client.Kill(); }
    catch { /* The process cannot be killed at this time. */ }
    }
Conclusion:
Alright, so we have a great working GUI for your server and my example project. Feel free to customize your GUI in any way you want. Explore the properties window for the GUI and the components in the GUI (such as your text box console). Here's the final product of my example GUI project:



I made it 90% opaque just to show you something a bit different. Keep it simple if you're running it on a server though (do 100% opaque or better use the console mode). So that's it. Congrats on making a GUI from scratch. Good luck with your project. Feel free to check out mine as well (in my signature where I have a lot of other releases that you could also check out).

Post a picture of your result because I'd love to see it.
Cheers,
Spirited Fang
Spirited is offline  
Thanks
2 Users
Old 04/13/2013, 15:44   #2
 
Super Aids's Avatar
 
elite*gold: 0
Join Date: Dec 2012
Posts: 1,761
Received Thanks: 950
Okay one thing. Seeing as you never run both the console and windows form application at the same time, why not just run the windows form on the main thread and then start the server from its constructor or Form_Load event?
Super Aids is offline  
Old 04/13/2013, 21:28   #3
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,283
Received Thanks: 4,192
Quote:
Originally Posted by Super Aids View Post
Okay one thing. Seeing as you never run both the console and windows form application at the same time, why not just run the windows form on the main thread and then start the server from its constructor or Form_Load event?
The reason I have people in this tutorial making the GUI run on another thread other than the main thread is because the main thread will always have priority. The advantage of starting the GUI on a new thread is that you can make it into a background thread or a thread that has a much lower priority than the thread that the server runs on.
Spirited is offline  
Old 04/13/2013, 23:07   #4
 
.Ryu's Avatar
 
elite*gold: 0
Join Date: Dec 2009
Posts: 583
Received Thanks: 119
Cool.
.Ryu is offline  
Old 04/14/2013, 00:12   #5
 
Super Aids's Avatar
 
elite*gold: 0
Join Date: Dec 2012
Posts: 1,761
Received Thanks: 950
Quote:
Originally Posted by Fаng View Post
The reason I have people in this tutorial making the GUI run on another thread other than the main thread is because the main thread will always have priority. The advantage of starting the GUI on a new thread is that you can make it into a background thread or a thread that has a much lower priority than the thread that the server runs on.
You could always change the Thread Priorities lol.
Super Aids is offline  
Old 04/14/2013, 00:49   #6
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,283
Received Thanks: 4,192
Quote:
Originally Posted by Super Aids View Post
You could always change the Thread Priorities lol.
"The main thread will always have priority." Yes, you can change the priority of the main thread (kind of) using Thread.CurrentThread; however, as I stated, the main thread will always have priority. It's because of the COM threading model and the way C# manages the main thread. It will always give higher performance than other threads being created in the apartment model selected. You can do it however which way you desire, but that is my understanding of it.
Spirited is offline  
Old 04/14/2013, 01:28   #7
 
Super Aids's Avatar
 
elite*gold: 0
Join Date: Dec 2012
Posts: 1,761
Received Thanks: 950
Yeah, but remember your server does not run on the main thread anyways.
Super Aids is offline  
Old 04/14/2013, 02:35   #8
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,283
Received Thanks: 4,192
Quote:
Originally Posted by Super Aids View Post
Yeah, but remember your server does not run on the main thread anyways.
Not everyone has an asynchronous socket system, and not every server application runs like Impulse's Trinity server. This is a general guide and I'm just making general assumptions. You don't have to follow the tutorial exactly - you have the freedom to make your own choices and program it however which way you feel works best for your application.
Spirited is offline  
Old 04/14/2013, 03:19   #9
 
Super Aids's Avatar
 
elite*gold: 0
Join Date: Dec 2012
Posts: 1,761
Received Thanks: 950
Quote:
Originally Posted by Fаng View Post
Not everyone has an asynchronous socket system
That is ones own disadvantage though.

Quote:
Originally Posted by Fаng View Post
and not every server application runs like Impulse's Trinity server.
What has that to do with anything?

Quote:
Originally Posted by Fаng View Post
This is a general guide and I'm just making general assumptions. You don't have to follow the tutorial exactly - you have the freedom to make your own choices and program it however which way you feel works best for your application.
I know this is a general tutorial, I am just pointing things out lol. Jesus, getting worked up much?

Feeling buff?
Super Aids is offline  
Thanks
1 User
Old 04/15/2013, 23:06   #10


 
KraHen's Avatar
 
elite*gold: 0
Join Date: Jul 2006
Posts: 2,216
Received Thanks: 794


I feel buff.
KraHen is offline  
Old 04/16/2013, 00:18   #11


 
Korvacs's Avatar
 
elite*gold: 20
Join Date: Mar 2006
Posts: 6,126
Received Thanks: 2,518
Quote:
Originally Posted by Super Aids View Post
Yeah, but remember your server does not run on the main thread anyways.
Its generally good practice to not use the main thread for anything really, so this is more than acceptable, I mean if your willing to argue that the main thread should be used for the GUI then you should also be arguing equally that the rest of the server run on it too... right?
Korvacs is offline  
Thanks
2 Users
Reply


Similar Threads Similar Threads
[Guide] How to Create a Graphic User Interface (GUI)
04/13/2013 - CO2 PServer Guides & Releases - 98 Replies
Luke, an administrator here, has decided that I am to be stripped of all my rights to develop here. I'm to be banned shortly simply because I own a board. I did nothing to instigate this, and I'm sorry you will be affected by this as well (if you're reading this). After years of developing here, I won't be a member of a community so willing to take everything away. This work will remain on my board (since they seem to want competition). Best regards.
Graphical User Interface (GUI)
10/06/2012 - Conquer Online 2 - 3 Replies
Hello, Well a long time a go there was a release for how to make a Graphical User Interface (GUI) but i can't seem to find it anymore. :confused: Yes used search Help is appreciated ;)



All times are GMT +1. The time now is 11:23.


Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2026 elitepvpers All Rights Reserved.