Jump to content

  • Log In with Google      Sign In   
  • Create Account


Xanather

Member Since 24 Apr 2012
Offline Last Active Jun 12 2014 06:02 AM

Topics I've Started

Modding API

13 August 2013 - 08:46 AM

I am developing a 2D sidescroller similar to terraria and starbound, after 3 months I have written my own hard coded "engine" for the game that features lighting, tile management, world management, entity management, networking, input, user interface management, rendering, and some others...

 

My question is how would a modding API be developed, I have a feeling I am too far down the track for such an easy implementation. I am using C# 5.0 (.net 4.5) with MonoGame. This is also the first time of me having a shot at developing a real game, I still would consider myself "newbie".

Since its C# I am leaning towards reflection and importing local libraries, this seems like it would be a security issue however. I do not have much experience with reflection but I am sure I could easily pick it up.

 

Some technical aspects of that game are:
1. The game is completely server-based, hence at the moment there is no singleplayer mode since start of development has been for multiplayer.
2. Uses TCP for networking.

3. The client and server will be obfuscated, eliminating easy .net decompiled modding.

4. Some part of the game can already be modded only server-side to see client-side effects (even though the client executable was not touched).

5. The server has all authority.
 

Thoughts?


Servers and Encryption

19 April 2013 - 08:58 PM

Ive not asked a question here for a while, but anyway.

 

My game will have server based multiplayer, players connect to the server, create a account and then play the game with that account on the server.

 

The account data is saved server side (1 file per account in a directory - since I want to allow server owners to transfer accounts to other servers by basically copying the file). Only the password of the account is encrypted in that file.

 

The server software will be available to anyone for free and I wanted idea's on how I could deal with malicious server owners who want try decrypt the passwords? Obviously the encryption key for each server out there would need to be the same so that the passing of account files between servers is compatible.

 

My concern is that I am working with C#, meaning the server assembly could be easily decompiled and the encryption key is easily obtained.

TLDR: Ideas on approaching server owners who want to decrypt player's accounts passwords for malicious activities?

 

I already know how do implement 128-bit AES encryption, but it seems useless if the key can be found

 

All replies are appriciated, thanks.

edit: I'm not concerned about server owners hacking their way into a game account, but rather logging into other websites in which the user may have the same password and/or username.


Goodbye Start button?

24 March 2013 - 05:29 AM

I heard somewhere that windows 9/blue wont have the start button either. I personally see this as a disappointment, the start screen is designed for touch screens not desktops.

Thoughts? Do you think this is a disappointment?

 

I don't want to sound stubborn, but I think I'm going to stay with Win7 for as long as a possibly can until new games and applications clease to function unless Microsoft makes non-awkward desktop OS before that happens.


3 Monitors

23 March 2013 - 05:53 AM

Im going to be replacing my old chunky TV with a new TV that will end up being mounted above my desk, and so I thought about 3 monitor setup and watching movies on the 3rd screen (the TV) whenever I want... This is just a idea, currently 2 monitors is fine obviously.

 

My current GTX 570 only supports 2 monitors. What would happen though if I were to get a very cheap GTS 620 (to allow for 3 monitors) how would it work? Do I need to set anything up with the nvidia drivers to make sure only my current GTX 570 does the processing?

If I were to run a game on the display that the GTS 620 was outputting what would happen? Would the GTX 570 still do the GPU processing?

 

All replies are appriciated smile.png


Quality of my code

11 January 2013 - 04:03 AM

I haven't done much network programming lately so I decided to make a small program. I quickly made this small program within 2 days, it uses .net's TcpClient and TcpListener classes.

 

All the program does is transfer files to/from computers. Server mode of the program accepts files, while client mode of the program sends files.

 

I would like any experienced (networking) programmers to tell me what I should improve on.

 

Looking at the code now I would:

 

1. try and somehow make reading the file and uploading the file happen on different threads (which will probably make the transfer faster). Same with downloading/saving the file.

 

2. split the code up a bit mode, its mostly crammed into one method - how would I do this though?

 

Here are the 4 classes used in the program:

 

Program.cs...

//By xanather.
using System;

namespace Transfar
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Transfar - Clean and Fast TCP File Transfers";
            Console.WriteLine("Loaded: Transfar v1.0");
            if (args.Length == 0)
            {
                ConsoleColor color = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("This executable needs to be passed some arguments...");
                Console.ForegroundColor = color;
                ShowHelp();
                Console.Write("Press any key to close this program... ");
                Console.ReadKey();
                return;
            }
            else
            {
                if (args[0] == "-server")
                {
                    Server server;
                    server = new Server();
                    server.Start(args);
                }
                else if (args[0] == "-client")
                {
                    Client client;
                    client = new Client();
                    client.Start(args);
                }
                else
                {
                    ConsoleColor color = Console.ForegroundColor;
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("Invalid argument(s). Here is the list of arguments...");
                    Console.ForegroundColor = color;
                    ShowHelp();
                    Console.Write("Press any key to close this program... ");
                    Console.ReadKey();
                    return;
                }
            }
        }
        static void ShowHelp()
        {
            Console.WriteLine("Available arguments (commands) for this application:");
            Console.WriteLine("Argument\t\tDescription");
            Console.WriteLine("-server [dir] [port]\n");
            Console.WriteLine("\t\t\tStarts the application in server mode so the");
            Console.WriteLine("\t\t\tapplication can receive and download files sent by");
            Console.WriteLine("\t\t\tTransfar clients. Port forwarding on the router");
            Console.WriteLine("\t\t\tmay be required so that the server can listen for");
            Console.WriteLine("\t\t\tinternet connections.\n");
            Console.WriteLine("\t\t\tThe [dir] argument specifies the folder/directory");
            Console.WriteLine("\t\t\tthe server should place received/downloaded files");
            Console.WriteLine("\t\t\tfrom clients. This argument is required.\n");
            Console.WriteLine("\t\t\tThe [port] argument specifies the port in which the");
            Console.WriteLine("\t\t\tserver should listen to for accepting Transfer client");
            Console.WriteLine("\t\t\tconnections. Default port is 5655. This argument is");
            Console.WriteLine("\t\t\toptional.\n");
            Console.WriteLine("-client [address] [file] [port]\n");
            Console.WriteLine("\t\t\tStarts the application in client mode so the");
            Console.WriteLine("\t\t\tapplication can send and upload files to a Transfar");
            Console.WriteLine("\t\t\tserver.\n");
            Console.WriteLine("\t\t\tThe [address] argument specifies the server's IP");
            Console.WriteLine("\t\t\tin which to connect to. This argument is required.\n");
            Console.WriteLine("\t\t\tThe [file] argument specifies the file on disk");
            Console.WriteLine("\t\t\tthe client should send/upload to the server.");
            Console.WriteLine("\t\t\tThis argument is required.\n");
            Console.WriteLine("\t\t\tThe [port] argument specifies which port the client");
            Console.WriteLine("\t\t\tshould use to connect to Transfar servers of the same");
            Console.WriteLine("\t\t\tport. Default port is 5655. This argument is optional.\n");
        }
    }
}

ArrayHelper.cs...

//By xanather
using System;

namespace Transfar
{
    static class ArrayHelper
    {
        public static bool Equals(byte[] a, byte[] b)
        {
            if (a.Length != b.Length)
            {
                return false;
            }
            for (int i = 0; i < a.Length; i++)
            {
                if (a[i] != b[i])
                {
                    return false;
                }
            }
            return true;
        }
    }
}

Client.cs...

//By xanather
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;

namespace Transfar
{
    class Client
    {
        public static readonly byte[] clientVerify = new byte[] { 6, 2, 5, 1, 255 };
        public string srcFile;
        public int port;
        public string address;
        public void Start(string[] args)
        {
            //get address argument
            if (args.Length > 1)
            {
                address = args[1];
            }
            else
            {
                ConsoleColor color = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("No IP address has been entered.");
                Console.WriteLine("It is a required argument.");
                Console.ForegroundColor = color;
                Console.Write("Press any key to close this program... ");
                Console.ReadKey();
                return;
            }
            //get file argument
            if (args.Length > 2)
            {
                if (File.Exists(args[2]))
                {
                    srcFile = args[2];
                }
                else
                {
                    ConsoleColor color = Console.ForegroundColor;
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("The file specified does not exist.");
                    Console.WriteLine("It is a required argument.");
                    Console.ForegroundColor = color;
                    Console.Write("Press any key to close this program... ");
                    Console.ReadKey();
                    return;
                }
            }
            else
            {
                ConsoleColor color = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("No file location has been entered.");
                Console.WriteLine("It is a required argument.");
                Console.ForegroundColor = color;
                Console.Write("Press any key to close this program... ");
                Console.ReadKey();
                return;
            }
            if (args.Length > 3)
            {
                try
                {
                    port = int.Parse(args[3]);
                    if (port < 0 || port > 65565)
                    {
                        throw new FormatException();
                    }
                }
                catch (FormatException)
                {
                    ConsoleColor color = Console.ForegroundColor;
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("Invalid port argument...");
                    Console.ForegroundColor = color;
                    Console.Write("Press any key to close this program... ");
                    Console.ReadKey();
                    return;
                }
            }
            else
            {
                port = Server.defaultPort;
            }
            //check the size of the file
            try
            {
                long fileSize = checked(new FileInfo(srcFile).Length);
            }
            catch (OverflowException)
            {
                ConsoleColor color = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("The file is too big! The maximum size supported is " + long.MaxValue + " bytes.");
                Console.ForegroundColor = color;
                Console.Write("Press any key to close this program... ");
                Console.ReadKey();
                return;
            }
            ProcessConnection();
        }
        public void ProcessConnection()
        {
            TcpClient client;
            NetworkStream stream;
            try
            {
                Console.WriteLine("Attempting to connect...");
                client = new TcpClient(address, port);
                stream = client.GetStream();
            }
            catch (SocketException e)
            {
                ConsoleColor color = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Cannot connect to server.");
                Console.WriteLine(e.Message);
                Console.ForegroundColor = color;
                Console.Write("Press any key to close this program... ");
                Console.ReadKey();
                return;
            }
            Console.WriteLine("Connected to server.");
            int readSize;
            int readAmount;
            byte[] readBuffer;
            int readAmountTotal;
            byte[] writeBuffer;
            byte[] writeBuffer1;
            //send client verification
            stream.Write(clientVerify, 0, clientVerify.Length);
            //read server verification
            readAmount = Server.serverVerify.Length;
            readBuffer = new byte[readAmount];
            readAmountTotal = readAmount;
            while (readAmount != 0)
            {
                readSize = stream.Read(readBuffer, readAmountTotal - readAmount, readAmount);
                readAmount -= readSize;
            }
            if (!ArrayHelper.Equals(readBuffer, Server.serverVerify))
            {
                stream.Close();
                client.Close();
                ConsoleColor color = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Disconnected, invalid server.");
                Console.ForegroundColor = color;
                Console.Write("Press any key to close this program... ");
                Console.ReadKey();
                return;
            }
            //write file name
            string fileName = Path.GetFileName(srcFile);
            writeBuffer1 = Encoding.UTF8.GetBytes(fileName);
            writeBuffer = new byte[writeBuffer1.Length + 1];
            writeBuffer[0] = (byte)writeBuffer1.Length;
            Buffer.BlockCopy(writeBuffer1, 0, writeBuffer, 1, writeBuffer1.Length);
            stream.Write(writeBuffer, 0, writeBuffer.Length);
            //read if file already exists in server directory
            stream.Read(readBuffer, 0, 1);
            if (readBuffer[0] == 0)
            {
                stream.Close();
                client.Close();
                ConsoleColor color = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Disconnected, the file {0} already exists in the server directory.");
                Console.ForegroundColor = color;
                Console.Write("Press any key to close this program... ");
                Console.ReadKey();
                return;
            }
            //write the size (in bytes) of the file
            Console.WriteLine("Now uploading the file...");
            long fileSize = new FileInfo(srcFile).Length;
            stream.Write(BitConverter.GetBytes(fileSize), 0, 8);
            //start uploading the whole file
            long writeRemaining = fileSize;
            int percent = 0;
            int prevPercent = -1;
            using (FileStream fileStream = new FileStream(srcFile, FileMode.Open))
            {
                while (writeRemaining != 0)
                {
                    readAmount = short.MaxValue; //write 65565 chuncks.
                    if (readAmount > writeRemaining)
                    {
                        readAmount = (int)writeRemaining;
                    }
                    readBuffer = new byte[readAmount];
                    fileStream.Read(readBuffer, 0, readAmount);
                    try
                    {
                        stream.Write(readBuffer, 0, readAmount);
                    }
                    catch (IOException e)
                    {
                        stream.Close();
                        client.Close();
                        ConsoleColor color = Console.ForegroundColor;
                        Console.ForegroundColor = ConsoleColor.Cyan;
                        Console.WriteLine("Disconnected: " + e.Message);
                        Console.ForegroundColor = color;
                        Console.Write("Press any key to close this program... ");
                        Console.ReadKey();
                        return;
                    }
                    writeRemaining -= readAmount;
                    percent = (int)(((fileSize - writeRemaining) / (double)fileSize * 100));
                    if (percent != prevPercent)
                    {
                        prevPercent = percent;
                        Console.WriteLine("{0} - Upload at {1}%. {2}KB remaining ({3}KB/{4}KB).", fileName, percent, writeRemaining / 1024, (fileSize - writeRemaining) / 1024, fileSize / 1024);
                    }
                }
            }
            //write clientVerify for final handshake
            stream.Write(clientVerify, 0, clientVerify.Length);
            stream.Close();
            client.Close();
            Console.WriteLine("Upload complete!");
            Console.Write("Press any key to close this program... ");
            Console.ReadKey();
        }
    }
}

Server.cs...

//By xanather
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;

namespace Transfar
{
    class Server
    {
        public static readonly byte[] serverVerify = new byte[]{10, 10, 35, 244, 21};
        public const int defaultPort = 5655;
        public int port;
        public string destDirectory;
        public AutoResetEvent connectionSignal = new AutoResetEvent(false);
        public TcpListener listener;
        public void Start(string[] args)
        {
            //get directory argument
            if (args.Length > 1)
            {
                if (!args[1].EndsWith(Path.DirectorySeparatorChar.ToString()))
                {
                    args[1] += Path.DirectorySeparatorChar;
                }
                if (Directory.Exists(args[1]))
                {
                    destDirectory = args[1];
                }
                else
                {
                    ConsoleColor color = Console.ForegroundColor;
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("The directory specified does not exist.");
                    Console.WriteLine("It is a required argument.");
                    Console.ForegroundColor = color;
                    Console.Write("Press any key to close this program... ");
                    Console.ReadKey();
                    return;
                }
            }
            else
            {
                ConsoleColor color = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("No destination directory has been entered.");
                Console.WriteLine("It is a required argument.");
                Console.ForegroundColor = color;
                Console.Write("Press any key to close this program... ");
                Console.ReadKey();
                return;
            }
            //get port argument
            if (args.Length > 2)
            {
                try
                {
                    port = int.Parse(args[2]);
                    if (port < 0 || port > 65565)
                    {
                        throw new FormatException();
                    }
                }
                catch (FormatException)
                {
                    ConsoleColor color = Console.ForegroundColor;
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("Invalid port argument...");
                    Console.ForegroundColor = color;
                    Console.Write("Press any key to close this program... ");
                    Console.ReadKey();
                    return;
                }
            }
            else
            {
                port = defaultPort;
            }
            StartListening();
        }
        public void StartListening()
        {
            listener = new TcpListener(IPAddress.Any, port);
            listener.Start();
            while (true)
            {
                Console.WriteLine("Listening for connections...");
                ProcessClientAsync();
                connectionSignal.WaitOne();
                connectionSignal.Reset();
            }
        }
        public async void ProcessClientAsync()
        {
            TcpClient client = await listener.AcceptTcpClientAsync();
            NetworkStream stream = client.GetStream();
            connectionSignal.Set();
            //connection variables
            string socketAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
            int socketPort = int.Parse(((IPEndPoint)client.Client.RemoteEndPoint).Port.ToString());
            int readSize;
            int readAmount;
            byte[] readBuffer;
            int readAmountTotal;
            //verify client connection
            readAmount = Client.clientVerify.Length;
            readBuffer = new byte[readAmount];
            readAmountTotal = readAmount;
            while (readAmount != 0)
            {
                readSize = stream.Read(readBuffer, readAmountTotal - readAmount, readAmount);
                readAmount -= readSize;
            }
            if (!ArrayHelper.Equals(readBuffer, Client.clientVerify))
            {
                stream.Close();
                client.Close();
                Console.WriteLine(string.Format("[{0}:{1}] Warning: Invalid connection request by this IP.", socketAddress, socketPort));
                return;
            }
            //send server verification
            stream.Write(serverVerify, 0, serverVerify.Length);
            Console.WriteLine(string.Format("[{0}:{1}] Connected.", socketAddress, socketPort));
            //read file name
            stream.Read(readBuffer, 0, 1);
            readAmount = readBuffer[0];
            readBuffer = new byte[readAmount];
            readAmountTotal = readAmount;
            while (readAmount != 0)
            {
                readSize = stream.Read(readBuffer, readAmountTotal - readAmount, readAmount);
                readAmount -= readSize;
            }
            string fileName = Encoding.UTF8.GetString(readBuffer);
            //write if file already exists in destDirectory
            if (File.Exists(destDirectory + fileName))
            {
                stream.Write(new byte[] { 0 }, 0, 1);
                stream.Close();
                client.Close();
                Console.WriteLine(string.Format("[{0}:{1}] Disconnected, tried to save a existing file ({2}).", socketAddress, socketPort, fileName));
                return;
            }
            else
            {
                stream.Write(new byte[] { 1 }, 0, 1);
            }
            //read the size (in bytes) of the file
            readAmount = 8;
            readBuffer = new byte[readAmount];
            readAmountTotal = readAmount;
            while (readAmount != 0)
            {
                readSize = stream.Read(readBuffer, readAmountTotal - readAmount, readAmount);
                readAmount -= readSize;
            }
            long fileSize = BitConverter.ToInt64(readBuffer, 0);
            //start downloading the whole file
            long readRemaining = fileSize;
            int percent = 0;
            int prevPercent = -1;
            Console.WriteLine(string.Format("[{0}:{1}] Now downloading file {2}. Total size: {3}KB.", socketAddress, socketPort, fileName, fileSize / 1024));
            using (FileStream fileStream = new FileStream(destDirectory + fileName, FileMode.CreateNew))
            {
                while (readRemaining != 0)
                {
                    readAmount = short.MaxValue; //read 65565 chuncks.
                    if (readAmount > readRemaining)
                    {
                        readAmount = (int)readRemaining;
                    }
                    readBuffer = new byte[readAmount];
                    readAmountTotal = readAmount;
                    while (readAmount != 0)
                    {
                        try
                        {
                            readSize = stream.Read(readBuffer, readAmountTotal - readAmount, readAmount);
                        }
                        catch (IOException e)
                        {
                            stream.Close();
                            client.Close();
                            Console.WriteLine(string.Format("[{0}:{1}] Disconnected: {2}", socketAddress, socketPort, e.Message));
                            Console.WriteLine(string.Format("[{0}:{1}] The file has not been received in full and may be corrupted.", socketAddress, socketPort, e.Message));
                            return;
                        }
                        readAmount -= readSize;
                    }
                    fileStream.Write(readBuffer, 0, readAmountTotal);
                    readRemaining -= readAmountTotal;
                    percent = (int)(((fileSize - readRemaining) / (double)fileSize) * 100);
                    if (percent != prevPercent)
                    {
                        prevPercent = percent;
                        Console.WriteLine("[{0}:{1}] {2} - Download at {3}%. {4}KB remaining ({5}KB/{6}KB).", socketAddress, socketPort, fileName, percent, readRemaining / 1024, (fileSize - readRemaining) / 1024, fileSize / 1024);
                    }
                }
            }
            //read clientVerify for final handshake
            readAmount = Client.clientVerify.Length;
            readBuffer = new byte[readAmount];
            readAmountTotal = readAmount;
            while (readAmount != 0)
            {
                readSize = stream.Read(readBuffer, readAmountTotal - readAmount, readAmount);
                readAmount -= readSize;
            }
            if (!ArrayHelper.Equals(readBuffer, Client.clientVerify))
            {
                stream.Close();
                client.Close();
                Console.WriteLine(string.Format("[{0}:{1}] Warning: Unspecified error, file may not be received properly.", socketAddress, socketPort));
                return;
            }
            else
            {
                Console.WriteLine(string.Format("[{0}:{1}] {2} - Download complete!", socketAddress, socketPort, fileName));
            }
            stream.Close();
            client.Close();
        }
    }
}

Ok, that ended up longer than I thought.

 

All replies are appriciated.

Thanks,

Xanather.


PARTNERS