diff --git a/server/CircleScape.csproj b/server/CircleScape.csproj
index 6176eaa..49f97d4 100644
--- a/server/CircleScape.csproj
+++ b/server/CircleScape.csproj
@@ -71,6 +71,7 @@
+
@@ -140,7 +141,8 @@
- XCOPY "$(ProjectDir)Assets" "$(TargetDir)" /Y
+ XCOPY "$(ProjectDir)Assets" "$(TargetDir)" /Y /E
+COPY "$(ProjectDir)config.ini" "$(TargetDir)" /Y
diff --git a/server/Configuration.cs b/server/Configuration.cs
new file mode 100644
index 0000000..75a4c22
--- /dev/null
+++ b/server/Configuration.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Square.INI;
+
+namespace CircleScape {
+ public static class Configuration {
+ private static SettingsFile Settings;
+
+ static Configuration() {
+ Settings = new SettingsFile(
+ "config.ini",
+ new List {
+ new SectionRules {
+ Name = "General",
+ Required = true,
+ RequiredFields = new string[] {
+ "Run Master",
+ "Master Port",
+ "Master Addr",
+ "Max Users"
+ }
+ },
+
+ new SectionRules {
+ Name = "Server",
+ AllowMultiple = true,
+ Required = true,
+ RequiredFields = new string[] {
+ "Id",
+ "Port"
+ }
+ }
+ }
+ );
+ }
+
+ public static Section Get(string section) {
+ return Settings[section];
+ }
+
+ public static Section General {
+ get {
+ return Settings["General"];
+ }
+ }
+
+ public static Section Servers {
+ get {
+ return Settings["Server"];
+ }
+ }
+ }
+}
diff --git a/server/Entrypoint.cs b/server/Entrypoint.cs
index 57ccdfc..6cf5440 100644
--- a/server/Entrypoint.cs
+++ b/server/Entrypoint.cs
@@ -11,6 +11,7 @@ using System.Net;
namespace CircleScape {
class Entrypoint {
static void Main(string[] args) {
+ foreach()
var server = new Kneesocks.Server(6770, PoolManager.Pending);
server.Start();
diff --git a/server/Libraries/Kneesocks/Connection.cs b/server/Libraries/Kneesocks/Connection.cs
index bf9df61..cfd849d 100644
--- a/server/Libraries/Kneesocks/Connection.cs
+++ b/server/Libraries/Kneesocks/Connection.cs
@@ -31,6 +31,7 @@ namespace Kneesocks {
private TcpClient Socket = null;
private NetworkStream Stream = null;
+ public Server Server { get; internal set; }
ReadBuffer Buffer;
private byte[] FirstTwoBytes = null;
@@ -93,6 +94,7 @@ namespace Kneesocks {
Socket = conn.Socket;
Stream = conn.Stream;
+ Server = conn.Server;
Buffer = conn.Buffer;
FirstTwoBytes = conn.FirstTwoBytes;
diff --git a/server/Libraries/Kneesocks/Server.cs b/server/Libraries/Kneesocks/Server.cs
index 0c929c6..0cfa808 100644
--- a/server/Libraries/Kneesocks/Server.cs
+++ b/server/Libraries/Kneesocks/Server.cs
@@ -7,19 +7,12 @@ using System.Net.Sockets;
using System.Net;
namespace Kneesocks {
- public class Server where T : Connection, new() {
- private TcpListener Socket;
- private Thread Listener = null;
- private Pool ConnectionPool = null;
- public bool Started { get; private set; } = false;
- public UInt16 Port { get; private set; }
-
- public Server(UInt16 port, Pool pool) {
- Port = port;
- Socket = new TcpListener(IPAddress.Any, port);
- Listener = new Thread(new ThreadStart(ListenThread));
- ConnectionPool = pool;
- }
+ public abstract class Server {
+ protected TcpListener Socket;
+ protected Thread Listener = null;
+ public bool Started { get; protected set; } = false;
+ public UInt16 Port { get; protected set; }
+ public object Configuration { get; protected set; }
public void Start() {
if(!Started) {
@@ -34,13 +27,26 @@ namespace Kneesocks {
Listener.Join();
}
}
+ }
- private void ListenThread() {
+ public class Server : Server where T : Connection, new() {
+ protected Pool ConnectionPool = null;
+
+ public Server(UInt16 port, Pool pool, object config = null) {
+ Port = port;
+ Socket = new TcpListener(IPAddress.Any, port);
+ Listener = new Thread(new ThreadStart(ListenThread));
+ ConnectionPool = pool;
+ Configuration = config;
+ }
+
+ protected void ListenThread() {
Socket.Start();
while(Started) {
if(Socket.Pending()) {
var templatedConnection = new T();
+ templatedConnection.Server = this;
templatedConnection.Initialize(Socket.AcceptTcpClient());
ConnectionPool.AddConnection(templatedConnection);
}
diff --git a/server/Libraries/Square/INI/Instance.cs b/server/Libraries/Square/INI/Instance.cs
index ebe0e8b..376a94b 100644
--- a/server/Libraries/Square/INI/Instance.cs
+++ b/server/Libraries/Square/INI/Instance.cs
@@ -1,13 +1,43 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Square.INI {
- class Instance {
- private Dictionary Data { get; set; }
+ public class Instance : IEnumerable> {
+ private Dictionary Data
+ = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ internal Instance() { }
+ internal void Push(string line) {
+ if(line.Contains('=')) {
+ var parts = line.Split(new char[] { '=' }, 2);
+ Data.Add(parts[0].Trim(), new Value(parts[1].Trim()));
+ } else
+ throw new FormatException("Line is not a key-value pair delimited by an equals sign.");
+ }
+
+ public Value this[string key] {
+ get {
+ if(Data.ContainsKey(key))
+ return Data[key];
+ else return null;
+ }
+ }
+
+ public bool ContainsKey(string key) {
+ return Data.ContainsKey(key);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() {
+ return Data.GetEnumerator();
+ }
+
+ IEnumerator> IEnumerable>.GetEnumerator() {
+ return Data.GetEnumerator();
+ }
}
}
diff --git a/server/Libraries/Square/INI/Section.cs b/server/Libraries/Square/INI/Section.cs
index aabdd7f..4b69259 100644
--- a/server/Libraries/Square/INI/Section.cs
+++ b/server/Libraries/Square/INI/Section.cs
@@ -6,10 +6,39 @@ using System.Text;
using System.Threading.Tasks;
namespace Square.INI {
- public class Section : IEnumerable {
+ public class Section : IEnumerable {
private List Instances;
- public IEnumerator GetEnumerator() {
+ internal Section() { }
+
+ internal Instance Push() {
+ Instances.Add(new Instance());
+ return Instances[Instances.Count - 1];
+ }
+
+ public string this[string key] {
+ get {
+ return Instances[0][key];
+ }
+ }
+
+ public Instance this[int i] {
+ get {
+ return Instances[i];
+ }
+ }
+
+ public int Count {
+ get {
+ return Instances.Count;
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() {
+ return Instances.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() {
return Instances.GetEnumerator();
}
}
diff --git a/server/Libraries/Square/INI/SectionRules.cs b/server/Libraries/Square/INI/SectionRules.cs
index 35ac38b..1326154 100644
--- a/server/Libraries/Square/INI/SectionRules.cs
+++ b/server/Libraries/Square/INI/SectionRules.cs
@@ -6,6 +6,9 @@ using System.Threading.Tasks;
namespace Square.INI {
public class SectionRules {
-
+ public string Name { get; set; }
+ public bool Required { get; set; } = true;
+ public bool AllowMultiple { get; set; } = false;
+ public string[] RequiredFields { get; set; } = new string[0];
}
}
diff --git a/server/Libraries/Square/INI/SettingsFile.cs b/server/Libraries/Square/INI/SettingsFile.cs
index 62b1e54..a595ea3 100644
--- a/server/Libraries/Square/INI/SettingsFile.cs
+++ b/server/Libraries/Square/INI/SettingsFile.cs
@@ -13,14 +13,47 @@ namespace Square.INI {
public SettingsFile(string path) {
var lines = File.ReadAllLines(path);
- string currentSection = null;
- foreach(var line in lines) {
+ Instance currentInstance = null;
+ foreach(var rawLine in lines) {
+ var line = rawLine.Trim();
+ if(line.StartsWith("!", "#", ";"))
+ continue;
+ if(line.StartsWith("[") && line.EndsWith("]")) {
+ var section = line.Substring(1, line.Length - 2);
+ if(!Sections.ContainsKey(section))
+ Sections.Add(section, new Section());
+
+ currentInstance = Sections[section].Push();
+ } else {
+ if(currentInstance != null)
+ currentInstance.Push(line);
+ else
+ throw new FormatException("Non-section line before any define sections in '"+ path +"'");
+ }
}
}
- public SettingsFile(string path, List rules) {
+ public SettingsFile(string path, List rules) : this(path) {
+ foreach(var rule in rules) {
+ var name = rule.Name;
+ if(ContainsSection(name)) {
+ var section = Sections[name];
+ if(!rule.AllowMultiple && section.Count > 1)
+ throw new FormatException("Section '"+ name +"' is not allowed to have multiple declarations in '"+ path +"'");
+
+ if(rule.RequiredFields.Length > 0) {
+ foreach(var instance in section) {
+ foreach(var field in rule.RequiredFields) {
+ if(instance.ContainsKey(field))
+ throw new FormatException("Expected field '"+ field +"' in section '" + name + "' was not found in '" + path + "'");
+ }
+ }
+ }
+ } else if(rule.Required)
+ throw new FormatException("Expected section '"+ name +"' was not found in '"+ path +"'");
+ }
}
public Section this[string section] {
@@ -30,5 +63,9 @@ namespace Square.INI {
else return null;
}
}
+
+ public bool ContainsSection(string section) {
+ return Sections.ContainsKey(section);
+ }
}
}
diff --git a/server/Libraries/Square/INI/Value.cs b/server/Libraries/Square/INI/Value.cs
new file mode 100644
index 0000000..3f30d6e
--- /dev/null
+++ b/server/Libraries/Square/INI/Value.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Square.INI {
+ public class Value {
+ private string Raw;
+
+ public Value(string raw) {
+ Raw = raw;
+ }
+
+ public static implicit operator string(Value value) {
+ return value.Raw;
+ }
+
+ public static implicit operator bool(Value value) {
+ return Boolean.TryParse(value.Raw, out bool retval)
+ ? retval
+ : false;
+ }
+
+ public static implicit operator int(Value value) {
+ return Int32.TryParse(value.Raw, out int retval)
+ ? retval
+ : 0;
+ }
+
+ public static implicit operator double(Value value) {
+ return Double.TryParse(value.Raw, out double retval)
+ ? retval
+ : 0;
+ }
+ }
+}
diff --git a/server/Libraries/Square/Square.csproj b/server/Libraries/Square/Square.csproj
index 8c25c5a..2cea401 100644
--- a/server/Libraries/Square/Square.csproj
+++ b/server/Libraries/Square/Square.csproj
@@ -48,6 +48,7 @@
+
diff --git a/server/Libraries/Square/StringExtensions.cs b/server/Libraries/Square/StringExtensions.cs
index 2636c39..e7f570b 100644
--- a/server/Libraries/Square/StringExtensions.cs
+++ b/server/Libraries/Square/StringExtensions.cs
@@ -29,5 +29,14 @@ namespace Square {
public static byte[] Base64DecodeRaw(this string str)
=> Convert.FromBase64String(str);
+
+ public static bool StartsWith(this string str, params string[] strings) {
+ foreach(var checkString in strings) {
+ if(str.StartsWith(checkString))
+ return true;
+ }
+
+ return false;
+ }
}
}
diff --git a/server/config.ini b/server/config.ini
new file mode 100644
index 0000000..0c615ed
--- /dev/null
+++ b/server/config.ini
@@ -0,0 +1,25 @@
+[General]
+; determines if this server instance should run the master server
+ Run Master = false
+
+; address and port of the master server
+;; if master server is in this instance, addr should be localhost
+;; and port determines what port the master server runs on
+Master Addr = localhost
+Master Port = 16670
+
+; this value used if the max users isn't specified in a server instance
+ Max Users = 100
+
+[Server]
+ Id = 1
+ Port = 6770
+Max Users = 300
+
+[Server]
+ Id = 2
+ Port = 6780
+
+[Server]
+ Id = 3
+ Port = 6790
\ No newline at end of file