Prechádzať zdrojové kódy

Split console tool from console service

Daniele Bartolini 11 rokov pred
rodič
commit
f35a9504b1

+ 45 - 0
tools/gui/console/EntryHistory.cs

@@ -0,0 +1,45 @@
+using System;
+
+namespace Crown
+{
+namespace Console
+{
+	public class EntryHistory
+	{
+		private uint MaxRecords = 0;
+		private uint Size = 0;
+		private uint Current = 0;
+		private string[] History = null;
+
+		// Creates a new hisory with room for max_records records.
+		public EntryHistory(uint max_records)
+		{
+			MaxRecords = max_records;
+			History = new string[max_records];
+		}
+
+		// Push a new string into the history.
+		public void Push(string text)
+		{
+			// Add command to history
+			History[Size] = text;
+			Size = Math.Min(Size + 1, MaxRecords - 1);
+			Current = Size;
+		}
+
+		// Returns the previous entry in the history.
+		public string Previous()
+		{
+			Current = Current > 0 ? Current -1 : 0;
+			return History[Current];
+		}
+
+		// Returns the next entry in the history.
+		public string Next()
+		{
+			Current = Math.Min(Current + 1, Size - 1);
+			return History[Current];
+		}
+	}
+} // namespace Console
+} // namespace Crown

+ 134 - 520
tools/gui/console/MainWindow.cs

@@ -6,588 +6,202 @@ using System.Net.Sockets;
 using System.Threading;
 using System.Text;
 using Newtonsoft.Json.Linq;
+using Crown.Console;
+using Crown.Core;
 
 public partial class MainWindow: Gtk.Window
 {
-	private System.Net.Sockets.Socket m_sock = null;
-	private TextTag tagInfo;
-	private TextTag tagWarning;
-	private TextTag tagError;
-	private TextTag tagDebug;
-
-	// Console history
-	private const uint MAX_HISTORY_ITEMS = 256;
-	private uint history_size = 0;
-	private uint history_current = 0;
-	private string[] history = new string[MAX_HISTORY_ITEMS];
-
-	// Connection
-	private string m_server_ip;
-	private int m_server_port;
-	private byte[] m_msg_header = new byte[4];
-	private byte[] m_byBuff = new byte[4096]; // Recieved data buffer
-	
+	private EntryHistory History = new EntryHistory(256);
+	private ConsoleClient Client = null;
+
+	private ActionGroup Actions = null;
+	private UIManager UI = new UIManager();
+
+	private ScrolledWindow scrolledwindow1;
+	private TextView textview1;
+	private Entry entry1;
+
+	private string Address = "127.0.0.1";
+	private int Port = 10001;
+
 	public MainWindow (): base (Gtk.WindowType.Toplevel)
 	{
 		Build ();
 
-		// Connection
-		m_server_ip = "127.0.0.1";
-		m_server_port = 10001;
+		ActionEntry[] entries = new ActionEntry[] {
+			new ActionEntry("Unpause", null, "Unpause", "<ctrl>U", null, OnUnpause),
+			new ActionEntry("EngineMenu", null, "_Engine", null, null, null),
+
+			new ActionEntry("RebuildAndReload", null, "Rebuild And Reload", null, null, OnRebuildAndReload),
+			new ActionEntry("ScriptMenu", null, "_Script", null, null, null),
+
+			new ActionEntry("Reconnect", null, "Reconnect", "<ctrl>R", null, null),
+			new ActionEntry("ConnectMenu", null, "_Connect", null, null, null)
+		};
+
+		Actions = new ActionGroup("group");
+		Actions.Add(entries);
+		UI.InsertActionGroup(Actions, 0);
+		UI.AddUiFromResource("Menu.xml");
+		AddAccelGroup(UI.AccelGroup);
+
+		MenuBar menuBar = (MenuBar)UI.GetWidget("/MenuBar");
+		vbox1.PackStart(menuBar, false, false, 0);
 
 		// Create tags for color-formatted text
-		tagInfo = new Gtk.TextTag ("info");
+		TextTag tagInfo = new Gtk.TextTag ("info");
 		tagInfo.BackgroundGdk = new Gdk.Color (255, 255, 255);
-
-		tagWarning = new Gtk.TextTag ("warning");
+		TextTag tagWarning = new Gtk.TextTag ("warning");
 		tagWarning.BackgroundGdk = new Gdk.Color (255, 255, 153);
-
-		tagError = new Gtk.TextTag ("error");
+		TextTag tagError = new Gtk.TextTag ("error");
 		tagError.BackgroundGdk = new Gdk.Color (255, 153, 153);
-
-		tagDebug = new Gtk.TextTag ("debug");
+		TextTag tagDebug = new Gtk.TextTag ("debug");
 		tagDebug.BackgroundGdk = new Gdk.Color (224, 224, 224);
 
+		textview1 = new TextView();
+		textview1.Editable = false;
+		textview1.CanFocus = false;
 		TextBuffer textbuffer1 = textview1.Buffer;
 		textbuffer1.TagTable.Add (tagInfo);
 		textbuffer1.TagTable.Add (tagWarning);
 		textbuffer1.TagTable.Add (tagError);
 		textbuffer1.TagTable.Add (tagDebug);
 
-		// Create completion dictionary
-		ListStore lua_api = new ListStore (typeof (string));
-
-		lua_api.AppendValues ("Device.frame_count");
-		lua_api.AppendValues ("Device.last_delta_time");
-		lua_api.AppendValues ("Device.start");
-		lua_api.AppendValues ("Device.stop");
-		lua_api.AppendValues ("Device.create_resource_package");
-		lua_api.AppendValues ("Device.destroy_resource_package");
-		lua_api.AppendValues ("Window.show");
-		lua_api.AppendValues ("Window.hide");
-		lua_api.AppendValues ("Window.get_size");
-		lua_api.AppendValues ("Window.get_position");
-		lua_api.AppendValues ("Window.resize");
-		lua_api.AppendValues ("Window.move");
-		lua_api.AppendValues ("Window.minimize");
-		lua_api.AppendValues ("Window.restore");
-		lua_api.AppendValues ("Window.is_resizable");
-		lua_api.AppendValues ("Window.set_resizable");
-		lua_api.AppendValues ("Window.show_cursor");
-		lua_api.AppendValues ("Window.get_cursor_xy");
-		lua_api.AppendValues ("Window.set_cursor_xy");
-		lua_api.AppendValues ("Window.title");
-		lua_api.AppendValues ("Window.set_title");
-		lua_api.AppendValues ("Math.deg_to_rad");
-		lua_api.AppendValues ("Math.rad_to_deg");
-		lua_api.AppendValues ("Math.next_pow_2");
-		lua_api.AppendValues ("Math.is_pow_2");
-		lua_api.AppendValues ("Math.ceil");
-		lua_api.AppendValues ("Math.floor");
-		lua_api.AppendValues ("Math.sqrt");
-		lua_api.AppendValues ("Math.inv_sqrt");
-		lua_api.AppendValues ("Math.sin");
-		lua_api.AppendValues ("Math.cos");
-		lua_api.AppendValues ("Math.asin");
-		lua_api.AppendValues ("Math.acos");
-		lua_api.AppendValues ("Math.tan");
-		lua_api.AppendValues ("Math.atan2");
-		lua_api.AppendValues ("Math.abs");
-		lua_api.AppendValues ("Math.fmod");
-		lua_api.AppendValues ("Vector2.new");
-		lua_api.AppendValues ("Vector2.val");
-		lua_api.AppendValues ("Vector2.add");
-		lua_api.AppendValues ("Vector2.sub");
-		lua_api.AppendValues ("Vector2.mul");
-		lua_api.AppendValues ("Vector2.div");
-		lua_api.AppendValues ("Vector2.dot");
-		lua_api.AppendValues ("Vector2.equals");
-		lua_api.AppendValues ("Vector2.lower");
-		lua_api.AppendValues ("Vector2.greater");
-		lua_api.AppendValues ("Vector2.length");
-		lua_api.AppendValues ("Vector2.squared_length");
-		lua_api.AppendValues ("Vector2.set_length");
-		lua_api.AppendValues ("Vector2.normalize");
-		lua_api.AppendValues ("Vector2.negate");
-		lua_api.AppendValues ("Vector2.get_distance_to");
-		lua_api.AppendValues ("Vector2.get_angle_between");
-		lua_api.AppendValues ("Vector2.zero");
-		lua_api.AppendValues ("Vector3.new");
-		lua_api.AppendValues ("Vector3.val");
-		lua_api.AppendValues ("Vector3.add");
-		lua_api.AppendValues ("Vector3.sub");
-		lua_api.AppendValues ("Vector3.mul");
-		lua_api.AppendValues ("Vector3.div");
-		lua_api.AppendValues ("Vector3.dot");
-		lua_api.AppendValues ("Vector3.cross");
-		lua_api.AppendValues ("Vector3.equals");
-		lua_api.AppendValues ("Vector3.lower");
-		lua_api.AppendValues ("Vector3.greater");
-		lua_api.AppendValues ("Vector3.length");
-		lua_api.AppendValues ("Vector3.squared_length");
-		lua_api.AppendValues ("Vector3.set_length");
-		lua_api.AppendValues ("Vector3.normalize");
-		lua_api.AppendValues ("Vector3.negate");
-		lua_api.AppendValues ("Vector3.get_distance_to");
-		lua_api.AppendValues ("Vector3.get_angle_between");
-		lua_api.AppendValues ("Vector3.zero");
-		lua_api.AppendValues ("Quaternion.new");
-		lua_api.AppendValues ("Quaternion.negate");
-		lua_api.AppendValues ("Quaternion.load_identity");
-		lua_api.AppendValues ("Quaternion.length");
-		lua_api.AppendValues ("Quaternion.conjugate");
-		lua_api.AppendValues ("Quaternion.inverse");
-		lua_api.AppendValues ("Quaternion.cross");
-		lua_api.AppendValues ("Quaternion.mul");
-		lua_api.AppendValues ("Quaternion.pow");
-		lua_api.AppendValues ("StringSetting.value");
-		lua_api.AppendValues ("StringSetting.synopsis");
-		lua_api.AppendValues ("StringSetting.update");
-		lua_api.AppendValues ("IntSetting.value");
-		lua_api.AppendValues ("IntSetting.synopsis");
-		lua_api.AppendValues ("IntSetting.min");
-		lua_api.AppendValues ("IntSetting.max");
-		lua_api.AppendValues ("IntSetting.update");
-		lua_api.AppendValues ("FloatSetting.value");
-		lua_api.AppendValues ("FloatSetting.synopsis");
-		lua_api.AppendValues ("FloatSetting.min");
-		lua_api.AppendValues ("FloatSetting.max");
-		lua_api.AppendValues ("FloatSetting.update");
-		lua_api.AppendValues ("Mouse.button_pressed");
-		lua_api.AppendValues ("Mouse.button_released");
-		lua_api.AppendValues ("Mouse.any_pressed");
-		lua_api.AppendValues ("Mouse.any_released");
-		lua_api.AppendValues ("Mouse.cursor_xy");
-		lua_api.AppendValues ("Mouse.set_cursor_xy");
-		lua_api.AppendValues ("Mouse.cursor_relative_xy");
-		lua_api.AppendValues ("Mouse.set_cursor_relative_xy");
-		lua_api.AppendValues ("Mouse.MB_LEFT");
-		lua_api.AppendValues ("Mouse.KB_MIDDLE");
-		lua_api.AppendValues ("Mouse.MB_RIGHT");
-		lua_api.AppendValues ("Keyboard.modifier_pressed");
-		lua_api.AppendValues ("Keyboard.button_pressed");
-		lua_api.AppendValues ("Keyboard.button_released");
-		lua_api.AppendValues ("Keyboard.any_pressed");
-		lua_api.AppendValues ("Keyboard.any_released");
-		lua_api.AppendValues ("Keyboard.TAB");
-		lua_api.AppendValues ("Keyboard.ENTER");
-		lua_api.AppendValues ("Keyboard.ESCAPE");
-		lua_api.AppendValues ("Keyboard.SPACE");
-		lua_api.AppendValues ("Keyboard.BACKSPACE");
-		lua_api.AppendValues ("Keyboard.KP_0");
-		lua_api.AppendValues ("Keyboard.KP_1");
-		lua_api.AppendValues ("Keyboard.KP_2");
-		lua_api.AppendValues ("Keyboard.KP_3");
-		lua_api.AppendValues ("Keyboard.KP_4");
-		lua_api.AppendValues ("Keyboard.KP_5");
-		lua_api.AppendValues ("Keyboard.KP_6");
-		lua_api.AppendValues ("Keyboard.KP_7");
-		lua_api.AppendValues ("Keyboard.KP_8");
-		lua_api.AppendValues ("Keyboard.KP_9");
-		lua_api.AppendValues ("Keyboard.F1");
-		lua_api.AppendValues ("Keyboard.F2");
-		lua_api.AppendValues ("Keyboard.F3");
-		lua_api.AppendValues ("Keyboard.F4");
-		lua_api.AppendValues ("Keyboard.F5");
-		lua_api.AppendValues ("Keyboard.F6");
-		lua_api.AppendValues ("Keyboard.F7");
-		lua_api.AppendValues ("Keyboard.F8");
-		lua_api.AppendValues ("Keyboard.F9");
-		lua_api.AppendValues ("Keyboard.F10");
-		lua_api.AppendValues ("Keyboard.F11");
-		lua_api.AppendValues ("Keyboard.F12");
-		lua_api.AppendValues ("Keyboard.HOME");
-		lua_api.AppendValues ("Keyboard.LEFT");
-		lua_api.AppendValues ("Keyboard.UP");
-		lua_api.AppendValues ("Keyboard.RIGHT");
-		lua_api.AppendValues ("Keyboard.DOWN");
-		lua_api.AppendValues ("Keyboard.PAGE_UP");
-		lua_api.AppendValues ("Keyboard.PAGE_DOWN");
-		lua_api.AppendValues ("Keyboard.LCONTROL");
-		lua_api.AppendValues ("Keyboard.RCONTROL");
-		lua_api.AppendValues ("Keyboard.LSHIFT");
-		lua_api.AppendValues ("Keyboard.RSHIFT");
-		lua_api.AppendValues ("Keyboard.CAPS_LOCK");
-		lua_api.AppendValues ("Keyboard.LALT");
-		lua_api.AppendValues ("Keyboard.RALT");
-		lua_api.AppendValues ("Keyboard.LSUPER");
-		lua_api.AppendValues ("Keyboard.RSUPER");
-		lua_api.AppendValues ("Keyboard.NUM_0");
-		lua_api.AppendValues ("Keyboard.NUM_1");
-		lua_api.AppendValues ("Keyboard.NUM_2");
-		lua_api.AppendValues ("Keyboard.NUM_3");
-		lua_api.AppendValues ("Keyboard.NUM_4");
-		lua_api.AppendValues ("Keyboard.NUM_5");
-		lua_api.AppendValues ("Keyboard.NUM_6");
-		lua_api.AppendValues ("Keyboard.NUM_7");
-		lua_api.AppendValues ("Keyboard.NUM_8");
-		lua_api.AppendValues ("Keyboard.NUM_9");
-		lua_api.AppendValues ("Keyboard.A");
-		lua_api.AppendValues ("Keyboard.B");
-		lua_api.AppendValues ("Keyboard.C");
-		lua_api.AppendValues ("Keyboard.D");
-		lua_api.AppendValues ("Keyboard.E");
-		lua_api.AppendValues ("Keyboard.F");
-		lua_api.AppendValues ("Keyboard.G");
-		lua_api.AppendValues ("Keyboard.H");
-		lua_api.AppendValues ("Keyboard.I");
-		lua_api.AppendValues ("Keyboard.J");
-		lua_api.AppendValues ("Keyboard.K");
-		lua_api.AppendValues ("Keyboard.L");
-		lua_api.AppendValues ("Keyboard.M");
-		lua_api.AppendValues ("Keyboard.N");
-		lua_api.AppendValues ("Keyboard.O");
-		lua_api.AppendValues ("Keyboard.P");
-		lua_api.AppendValues ("Keyboard.Q");
-		lua_api.AppendValues ("Keyboard.R");
-		lua_api.AppendValues ("Keyboard.S");
-		lua_api.AppendValues ("Keyboard.T");
-		lua_api.AppendValues ("Keyboard.U");
-		lua_api.AppendValues ("Keyboard.V");
-		lua_api.AppendValues ("Keyboard.W");
-		lua_api.AppendValues ("Keyboard.X");
-		lua_api.AppendValues ("Keyboard.Y");
-		lua_api.AppendValues ("Keyboard.Z");
-		lua_api.AppendValues ("Keyboard.a");
-		lua_api.AppendValues ("Keyboard.b");
-		lua_api.AppendValues ("Keyboard.c");
-		lua_api.AppendValues ("Keyboard.d");
-		lua_api.AppendValues ("Keyboard.e");
-		lua_api.AppendValues ("Keyboard.f");
-		lua_api.AppendValues ("Keyboard.g");
-		lua_api.AppendValues ("Keyboard.h");
-		lua_api.AppendValues ("Keyboard.i");
-		lua_api.AppendValues ("Keyboard.j");
-		lua_api.AppendValues ("Keyboard.k");
-		lua_api.AppendValues ("Keyboard.l");
-		lua_api.AppendValues ("Keyboard.m");
-		lua_api.AppendValues ("Keyboard.n");
-		lua_api.AppendValues ("Keyboard.o");
-		lua_api.AppendValues ("Keyboard.p");
-		lua_api.AppendValues ("Keyboard.q");
-		lua_api.AppendValues ("Keyboard.r");
-		lua_api.AppendValues ("Keyboard.s");
-		lua_api.AppendValues ("Keyboard.t");
-		lua_api.AppendValues ("Keyboard.u");
-		lua_api.AppendValues ("Keyboard.v");
-		lua_api.AppendValues ("Keyboard.w");
-		lua_api.AppendValues ("Keyboard.x");
-		lua_api.AppendValues ("Keyboard.y");
-		lua_api.AppendValues ("Keyboard.z");
-		lua_api.AppendValues ("ResourcePackage.load");
-		lua_api.AppendValues ("ResourcePackage.unload");
-		lua_api.AppendValues ("ResourcePackage.flush");
-		lua_api.AppendValues ("ResourcePackage.has_loaded");
-		lua_api.AppendValues("Camera.local_position");
-		lua_api.AppendValues("Camera.local_rotation");
-		lua_api.AppendValues("Camera.local_pose");
-		lua_api.AppendValues("Camera.world_position");
-		lua_api.AppendValues("Camera.world_rotation");
-		lua_api.AppendValues("Camera.world_pose");
-		lua_api.AppendValues("Camera.set_local_position");
-		lua_api.AppendValues("Camera.set_local_rotation");
-		lua_api.AppendValues("Camera.set_local_pose");
-		lua_api.AppendValues("Camera.set_projection_type");
-		lua_api.AppendValues("Camera.projection_type");
-		lua_api.AppendValues("Camera.fov");
-		lua_api.AppendValues("Camera.set_fov");
-		lua_api.AppendValues("Camera.aspect");
-		lua_api.AppendValues("Camera.set_aspect");
-		lua_api.AppendValues("Camera.near_clip_distance");
-		lua_api.AppendValues("Camera.set_near_clip_distance");
-		lua_api.AppendValues("Camera.far_clip_distance");
-		lua_api.AppendValues("Camera.set_far_clip_distance");
-		lua_api.AppendValues("Mesh.local_position");
-		lua_api.AppendValues("Mesh.local_rotation");
-		lua_api.AppendValues("Mesh.local_pose");
-		lua_api.AppendValues("Mesh.world_position");
-		lua_api.AppendValues("Mesh.world_rotation");
-		lua_api.AppendValues("Mesh.world_pose");
-		lua_api.AppendValues("Mesh.set_local_position");
-		lua_api.AppendValues("Mesh.set_local_rotation");
-		lua_api.AppendValues("Mesh.set_local_pose");
-		lua_api.AppendValues("Unit.local_position");
-		lua_api.AppendValues("Unit.local_rotation");
-		lua_api.AppendValues("Unit.local_pose");
-		lua_api.AppendValues("Unit.world_position");
-		lua_api.AppendValues("Unit.world_rotation");
-		lua_api.AppendValues("Unit.world_pose");
-		lua_api.AppendValues("Unit.set_local_position");
-		lua_api.AppendValues("Unit.set_local_rotation");
-		lua_api.AppendValues("Unit.set_local_pose");
-		lua_api.AppendValues("World.spawn_unit");
-		lua_api.AppendValues("World.play_sound");
-		lua_api.AppendValues("World.pause_sound");
-		lua_api.AppendValues("World.link_sound");
-		lua_api.AppendValues("World.set_listener");
-		lua_api.AppendValues("World.set_sound_position");
-		lua_api.AppendValues("World.set_sound_range");
-		lua_api.AppendValues("World.set_sound_volume");
-
-		entry1.Completion = new EntryCompletion ();
-		entry1.Completion.Model = lua_api;
-		entry1.Completion.TextColumn = 0;
+		scrolledwindow1 = new ScrolledWindow();
+		scrolledwindow1.Add(textview1);
+		vbox1.PackStart(scrolledwindow1, true, true, 0);
+
+		entry1 = new Entry();
+		entry1.KeyPressEvent += new KeyPressEventHandler(OnEntryKeyPressed);
+		entry1.Activated += new EventHandler(OnEntryActivated);
+		vbox1.PackStart(entry1, false, true, 0);
+
+		EnableMainMenu(false);
+		Actions.GetAction("ScriptMenu").Sensitive = false;
+		Client = new ConsoleClient();
+		Client.ConnectedEvent += OnConnected;
+		Client.DisconnectedEvent += OnDisconnected;
+		Client.MessageReceivedEvent += OnMessageReceived;
+		Connect(Address, Port);
+		ShowAll();
 	}
-	
-	public void Connect()
-	{
-		try
-		{
-			// Do nothing if connected
-			if( m_sock != null && m_sock.Connected )
-			{
-				return;
-			}
 
-			// Try to connect
-			m_sock = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+	protected void EnableMainMenu(bool enable)
+	{
+		Actions.GetAction("EngineMenu").Sensitive = enable;
+		// Actions.GetAction("ScriptMenu").Sensitive = enable;
+	}
 
-			// TODO: Input check
-			m_server_ip = ip_entry.Text;
-			m_server_port = Convert.ToInt16(port_entry.Text);
+	protected void OnConnected(object o, ConnectedArgs args)
+	{
+		EnableMainMenu(true);
+		LogInfo("Connected to " + args.Address + ":" + args.Port.ToString() + "\n");
+	}
 
-			// Define the Server address and port
-			IPEndPoint epServer = new IPEndPoint(IPAddress.Parse(m_server_ip), m_server_port);
+	protected void OnDisconnected(object o, DisconnectedArgs args)
+	{
+		EnableMainMenu(false);
+		LogInfo("Disconnected\n");
+	}
 
-			// Connect to server non-Blocking method
-			m_sock.Blocking = false;
-			m_sock.BeginConnect(epServer, new AsyncCallback(OnConnected), m_sock);
-		}
-		catch(Exception e)
-		{
-			WriteLog("Unable to connect to " + m_server_ip + ":" + m_server_port + "\n", tagInfo);
-		}
+	protected void Connect(string addr, int port)
+	{
+		LogInfo("Trying " + addr + ":" + port.ToString() + "\n");
+		Client.Connect(addr, port);
 	}
-	
-	public void OnConnected(IAsyncResult ar)
+
+	protected void OnMessageReceived(object o, MessageReceivedArgs args)
 	{
-		try
+		JObject obj = JObject.Parse(args.Json);
+		if (obj["type"].ToString() == "message")
 		{
-			System.Net.Sockets.Socket sock = (System.Net.Sockets.Socket)ar.AsyncState;
+			string severity = obj["severity"].ToString();
+			string message = obj["message"].ToString();
 
-			sock.EndConnect(ar);
-			WriteLog("Connected to " + sock.RemoteEndPoint.ToString() + "\n", tagInfo);
-
-			// Start receiving stuff
-			Receive(sock);
-		}
-		catch( Exception ex )
-		{
-			WriteLog("Unable to connect to " + m_server_ip + ":" + m_server_port + "\n", tagInfo);
+			if (severity == "info") LogInfo(message);
+			else if (severity == "warning") LogWarning(message);
+			else if (severity == "error") LogError(message);
+			else if (severity == "debug") LogDebug(message);
 		}
 	}
-	
-	public void Receive(System.Net.Sockets.Socket sock)
+
+	protected void OnEntryActivated (object sender, EventArgs e)
 	{
-		try
-		{
-			sock.BeginReceive(m_msg_header, 0, 4, SocketFlags.None,
-			                  new AsyncCallback(OnReceived), sock);
-		}
-		catch( Exception ex )
+		string text = entry1.Text;
+		text = text.Trim ();
+
+		// Do processing only if we have text
+		if (text.Length > 0)
 		{
-			Console.Write("Receive failed!");
+			History.Push(text);
+			Client.SendScript(text);
+			LogInfo("> " + text + "\n");
 		}
+
+		entry1.Text = "";
 	}
-	
-	public void OnReceived(IAsyncResult ar)
+
+	protected void OnEntryKeyPressed (object o, KeyPressEventArgs args)
 	{
-		try
-		{
-			System.Net.Sockets.Socket sock = (System.Net.Sockets.Socket)ar.AsyncState;
-
-			int nBytesRec = sock.EndReceive(ar);
-			if(nBytesRec > 0)
-			{
-				// Read the message
-				int bytesRead = sock.Receive(m_byBuff, BitConverter.ToInt32(m_msg_header, 0), SocketFlags.None);
-				// Wrote the data to the List
-				string received = Encoding.ASCII.GetString( m_byBuff, 0, bytesRead );
-
-				JObject obj = JObject.Parse(received);
-				if (obj["type"].ToString() == "message")
-				{
-					string severity = obj["severity"].ToString();
-					string message = obj["message"].ToString();
-
-					if (severity == "info")
-					{
-						WriteLog(message, tagInfo);
-					}
-					else if (severity == "warning")
-					{
-						WriteLog(message, tagWarning);
-					}
-					else if (severity == "error")
-					{
-						WriteLog(message, tagError);
-					}
-					else if (severity == "debug")
-					{
-						WriteLog(message, tagDebug);
-					}
-				}
-				else
-				{
-					WriteLog("Unknown response from server\n", tagInfo);
-				}
-
-				// If the connection is still usable restablish the callback
-				Receive(sock);
-			}
-			else
-			{
-				// If no data was recieved then the connection is probably dead
-				WriteLog ("Server closed connection\n", tagInfo);
-				sock.Shutdown( SocketShutdown.Both );
-				sock.Close();
-			}
-		}
-		catch( Exception ex )
+		string text = "";
+
+		switch (args.Event.Key)
 		{
-			WriteLog ("Unknown error during receive\n", tagInfo);
+			case Gdk.Key.Down: text = History.Next(); break;
+			case Gdk.Key.Up: text = History.Previous(); break;
+			default: return; // Ignore other keys
 		}
-	}
 
-	protected void WriteLog(string text, TextTag tag)
-	{
-		Gtk.Application.Invoke (delegate
-		{
-			TextIter endIter = textview1.Buffer.EndIter;
-			textview1.Buffer.Insert(ref endIter, text);
-			endIter.BackwardChars(text.Length);
-			textview1.Buffer.ApplyTag(tag, endIter, textview1.Buffer.EndIter);
-			textview1.ScrollToMark(textview1.Buffer.CreateMark("bottom", textview1.Buffer.EndIter, false), 0, true, 0.0, 1.0);
-		});
+		entry1.Text = text;
+		entry1.Position = entry1.Text.Length;
+		args.RetVal = true;
 	}
 
-	protected void OnDeleteEvent (object sender, DeleteEventArgs a)
+	protected void OnUnpause(object o, EventArgs args)
 	{
-		Application.Quit ();
-		a.RetVal = true;
+		Client.Send("{\"type\":\"command\",\"command\":\"unpause\"}");
 	}
 
-	private static void OnSent(IAsyncResult ar)
+	protected void OnRebuildAndReload(object o, EventArgs args)
 	{
-		try
-		{
-			// Retrieve the socket from the state object.
-			System.Net.Sockets.Socket sock = (System.Net.Sockets.Socket) ar.AsyncState;
-
-			// Complete sending the data to the remote device.
-			sock.EndSend(ar);
-		}
-		catch (Exception e)
-		{
-			Console.WriteLine(e.ToString());
-		}
+		Client.Send("{\"type\":\"command\",\"command\":\"reload\"}");
 	}
 
-	protected void Send(string data)
+	// Logging
+	private void WriteLog(string text, string tag)
 	{
-		try {
-			m_sock.Send(BitConverter.GetBytes(data.Length));
-			m_sock.Send(Encoding.ASCII.GetBytes (data));
-		} catch (Exception e) {
-			Console.WriteLine (e.ToString ());
-		}
+		Gtk.Application.Invoke (delegate {
+			TextIter endIter = textview1.Buffer.EndIter;
+			textview1.Buffer.Insert(ref endIter, text);
+			endIter.BackwardChars(text.Length);
+			textview1.Buffer.ApplyTag(textview1.Buffer.TagTable.Lookup(tag), endIter, textview1.Buffer.EndIter);
+			textview1.ScrollToMark(textview1.Buffer.CreateMark("bottom", textview1.Buffer.EndIter, false), 0, true, 0.0, 1.0);
+		});
 	}
 
-	protected void SendScript(String script)
+	private void LogInfo(string text)
 	{
-		string json = "{\"type\":\"script\",\"script\":\"" + script + "\"}";
-		Send(json);
+		WriteLog(text, "info");
 	}
 
-	protected void SendCommand(String command)
+	private void LogWarning(string text)
 	{
-		char[] delimiterChars = { ' ', '\t' };
-		string[] words = command.Split(delimiterChars);
-
-		string cmd = words[0];
-		string resource_type = words[1];
-		string resource_name = words[2];
-	
-		string json = "{\"type\":\"command\",\"command\":\"" + cmd + "\","
-					+ "\"resource_type\":" + "\"" + resource_type + "\","
-					+ "\"resource_name\":" + "\"" + resource_name + "\"}";
-
-		Send (json);
+		WriteLog(text, "warning");
 	}
 
-	protected void OnEntryActivated (object sender, EventArgs e)
+	private void LogError(string text)
 	{
-		string text = entry1.Text;
-		text = text.Trim ();
-
-		// Do processing only if we have text
-		if (text.Length > 0)
-		{
-			// Add command to history
-			history [history_size % MAX_HISTORY_ITEMS] = text;
-			history_size++;
-			history_current = history_size;
-
-			// Try to connect before sending any stuff
-			Connect();
-
-			// Sanitize entered text
-			string safe_text = text.Replace("\"", "\\\"");
-
-			if (safe_text[0] == '\\') {
-				SendCommand (safe_text.Substring(1));
-			} else {
-				SendScript (safe_text);	
-			}
-
-			// Log entered text
-			WriteLog ("> " + text + "\n", tagInfo);
-		}
-
-		entry1.Text = "";
+		WriteLog(text, "error");
 	}
 
-	protected void OnEntryKeyPressed (object o, KeyPressEventArgs args)
+	private void LogDebug(string text)
 	{
-		switch (args.Event.Key)
-		{
-			case Gdk.Key.Down:
-			{
-				if (history_current < history_size)
-				{
-					history_current++;
-				}
-				break;
-			}
-			case Gdk.Key.Up:
-			{
-				if (history_current > 0)
-				{
-					history_current--;
-				}
-				break;
-			}
-			default:
-			{
-				return;
-			}
-		}
-
-		if (history_size == history_current)
-		{
-			entry1.Text = "";
-		}
-		else
-		{
-			entry1.Text = history [history_current % MAX_HISTORY_ITEMS];
-			entry1.Position = entry1.Text.Length;
-		}
-
-		args.RetVal = true;
+		WriteLog(text, "debug");
 	}
 
-	protected void OnConnectClicked (object sender, EventArgs e)
+	private void OnDeleteEvent (object sender, DeleteEventArgs a)
 	{
-		Connect ();
+		Application.Quit ();
+		a.RetVal = true;
 	}
 }

+ 13 - 0
tools/gui/console/Menu.xml

@@ -0,0 +1,13 @@
+<ui>
+	<menubar name="MenuBar">
+		<menu action="EngineMenu">
+			<menuitem action="Unpause"></menuitem>
+		</menu>
+		<menu action="ScriptMenu">
+			<menuitem action="RebuildAndReload"></menuitem>
+		</menu>
+		<menu action="ConnectMenu">
+			<menuitem action="Reconnect"></menuitem>
+		</menu>
+	</menubar>
+</ui>

+ 23 - 26
tools/gui/console/console.csproj

@@ -30,40 +30,37 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
-    <Reference Include="gtk-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
-      <SpecificVersion>False</SpecificVersion>
-    </Reference>
-    <Reference Include="gdk-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
-      <SpecificVersion>False</SpecificVersion>
-    </Reference>
-    <Reference Include="glib-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
-      <SpecificVersion>False</SpecificVersion>
-    </Reference>
-    <Reference Include="glade-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
-      <SpecificVersion>False</SpecificVersion>
-    </Reference>
-    <Reference Include="pango-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
-      <SpecificVersion>False</SpecificVersion>
-    </Reference>
-    <Reference Include="atk-sharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
-      <SpecificVersion>False</SpecificVersion>
-    </Reference>
     <Reference Include="Mono.Posix" />
     <Reference Include="Newtonsoft.Json">
       <HintPath>..\..\..\third\jsonnet\Newtonsoft.Json.dll</HintPath>
     </Reference>
+    <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+    <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+    <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
+    <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
   </ItemGroup>
   <ItemGroup>
-    <EmbeddedResource Include="gtk-gui\gui.stetic">
-      <LogicalName>gui.stetic</LogicalName>
-    </EmbeddedResource>
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="gtk-gui\generated.cs" />
-    <Compile Include="MainWindow.cs" />
-    <Compile Include="gtk-gui\MainWindow.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="EntryHistory.cs" />
+    <Compile Include="gtk-gui\generated.cs" />
+    <Compile Include="gtk-gui\MainWindow.cs" />
+    <Compile Include="MainWindow.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <ProjectReference Include="..\core\core.csproj">
+      <Project>{B26EAA66-08A9-493F-9C9F-85F7F5C57304}</Project>
+      <Name>core</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="gtk-gui\gui.stetic">
+      <LogicalName>gui.stetic</LogicalName>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Menu.xml">
+      <DeployService-Deploy>True</DeployService-Deploy>
+      <LogicalName>Menu.xml</LogicalName>
+    </EmbeddedResource>
+  </ItemGroup>
 </Project>

+ 0 - 97
tools/gui/console/gtk-gui/MainWindow.cs

@@ -12,22 +12,6 @@ public partial class MainWindow
 	private global::Gtk.Action EditAction;
 	
 	private global::Gtk.VBox vbox1;
-	
-	private global::Gtk.MenuBar menubar1;
-	
-	private global::Gtk.HBox hbox1;
-	
-	private global::Gtk.Entry ip_entry;
-	
-	private global::Gtk.Entry port_entry;
-	
-	private global::Gtk.Button connect_button;
-	
-	private global::Gtk.ScrolledWindow scrolledwindow1;
-	
-	private global::Gtk.TextView textview1;
-	
-	private global::Gtk.Entry entry1;
 
 	protected virtual void Build ()
 	{
@@ -53,84 +37,6 @@ public partial class MainWindow
 		this.vbox1 = new global::Gtk.VBox ();
 		this.vbox1.Name = "vbox1";
 		this.vbox1.Spacing = 6;
-		// Container child vbox1.Gtk.Box+BoxChild
-		this.UIManager.AddUiFromString ("<ui><menubar name='menubar1'><menu name='FileAction1' action='FileAction1'/><menu name='EditAction' action='EditAction'/></menubar></ui>");
-		this.menubar1 = ((global::Gtk.MenuBar)(this.UIManager.GetWidget ("/menubar1")));
-		this.menubar1.Name = "menubar1";
-		this.vbox1.Add (this.menubar1);
-		global::Gtk.Box.BoxChild w2 = ((global::Gtk.Box.BoxChild)(this.vbox1 [this.menubar1]));
-		w2.Position = 0;
-		w2.Expand = false;
-		w2.Fill = false;
-		// Container child vbox1.Gtk.Box+BoxChild
-		this.hbox1 = new global::Gtk.HBox ();
-		this.hbox1.Name = "hbox1";
-		this.hbox1.Spacing = 6;
-		// Container child hbox1.Gtk.Box+BoxChild
-		this.ip_entry = new global::Gtk.Entry ();
-		this.ip_entry.WidthRequest = 261;
-		this.ip_entry.CanFocus = true;
-		this.ip_entry.Name = "ip_entry";
-		this.ip_entry.Text = global::Mono.Unix.Catalog.GetString ("Ip");
-		this.ip_entry.IsEditable = true;
-		this.ip_entry.InvisibleChar = '●';
-		this.hbox1.Add (this.ip_entry);
-		global::Gtk.Box.BoxChild w3 = ((global::Gtk.Box.BoxChild)(this.hbox1 [this.ip_entry]));
-		w3.Position = 0;
-		w3.Expand = false;
-		// Container child hbox1.Gtk.Box+BoxChild
-		this.port_entry = new global::Gtk.Entry ();
-		this.port_entry.CanFocus = true;
-		this.port_entry.Name = "port_entry";
-		this.port_entry.Text = global::Mono.Unix.Catalog.GetString ("Port");
-		this.port_entry.IsEditable = true;
-		this.port_entry.InvisibleChar = '●';
-		this.hbox1.Add (this.port_entry);
-		global::Gtk.Box.BoxChild w4 = ((global::Gtk.Box.BoxChild)(this.hbox1 [this.port_entry]));
-		w4.Position = 1;
-		w4.Expand = false;
-		// Container child hbox1.Gtk.Box+BoxChild
-		this.connect_button = new global::Gtk.Button ();
-		this.connect_button.CanFocus = true;
-		this.connect_button.Name = "connect_button";
-		this.connect_button.UseUnderline = true;
-		this.connect_button.Label = global::Mono.Unix.Catalog.GetString ("Connect");
-		this.hbox1.Add (this.connect_button);
-		global::Gtk.Box.BoxChild w5 = ((global::Gtk.Box.BoxChild)(this.hbox1 [this.connect_button]));
-		w5.Position = 2;
-		w5.Expand = false;
-		w5.Fill = false;
-		this.vbox1.Add (this.hbox1);
-		global::Gtk.Box.BoxChild w6 = ((global::Gtk.Box.BoxChild)(this.vbox1 [this.hbox1]));
-		w6.Position = 1;
-		w6.Expand = false;
-		w6.Fill = false;
-		// Container child vbox1.Gtk.Box+BoxChild
-		this.scrolledwindow1 = new global::Gtk.ScrolledWindow ();
-		this.scrolledwindow1.CanFocus = true;
-		this.scrolledwindow1.Name = "scrolledwindow1";
-		this.scrolledwindow1.ShadowType = ((global::Gtk.ShadowType)(1));
-		// Container child scrolledwindow1.Gtk.Container+ContainerChild
-		this.textview1 = new global::Gtk.TextView ();
-		this.textview1.CanFocus = true;
-		this.textview1.Name = "textview1";
-		this.textview1.Editable = false;
-		this.scrolledwindow1.Add (this.textview1);
-		this.vbox1.Add (this.scrolledwindow1);
-		global::Gtk.Box.BoxChild w8 = ((global::Gtk.Box.BoxChild)(this.vbox1 [this.scrolledwindow1]));
-		w8.Position = 2;
-		// Container child vbox1.Gtk.Box+BoxChild
-		this.entry1 = new global::Gtk.Entry ();
-		this.entry1.CanFocus = true;
-		this.entry1.Name = "entry1";
-		this.entry1.IsEditable = true;
-		this.entry1.InvisibleChar = '●';
-		this.vbox1.Add (this.entry1);
-		global::Gtk.Box.BoxChild w9 = ((global::Gtk.Box.BoxChild)(this.vbox1 [this.entry1]));
-		w9.PackType = ((global::Gtk.PackType)(1));
-		w9.Position = 3;
-		w9.Expand = false;
-		w9.Fill = false;
 		this.Add (this.vbox1);
 		if ((this.Child != null)) {
 			this.Child.ShowAll ();
@@ -139,8 +45,5 @@ public partial class MainWindow
 		this.DefaultHeight = 474;
 		this.Show ();
 		this.DeleteEvent += new global::Gtk.DeleteEventHandler (this.OnDeleteEvent);
-		this.connect_button.Clicked += new global::System.EventHandler (this.OnConnectClicked);
-		this.entry1.Activated += new global::System.EventHandler (this.OnEntryActivated);
-		this.entry1.KeyPressEvent += new global::Gtk.KeyPressEventHandler (this.OnEntryKeyPressed);
 	}
 }

+ 4 - 103
tools/gui/console/gtk-gui/gui.stetic

@@ -2,9 +2,9 @@
 <stetic-interface>
   <configuration>
     <images-root-path>..</images-root-path>
+    <target-gtk-version>2.12</target-gtk-version>
   </configuration>
   <import>
-    <widget-library name="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
     <widget-library name="../bin/Debug/console.exe" internal="true" />
   </import>
   <widget class="Gtk.Window" id="MainWindow" design-size="932 474">
@@ -34,112 +34,13 @@
         <property name="MemberName" />
         <property name="Spacing">6</property>
         <child>
-          <widget class="Gtk.MenuBar" id="menubar1">
-            <property name="MemberName" />
-            <node name="__gtksharp_125_Stetic_Editor_ActionMenuBar" type="Menubar">
-              <node type="Menu" action="FileAction1" />
-              <node type="Menu" action="EditAction" />
-            </node>
-          </widget>
-          <packing>
-            <property name="Position">0</property>
-            <property name="AutoSize">True</property>
-            <property name="Expand">False</property>
-            <property name="Fill">False</property>
-          </packing>
+          <placeholder />
         </child>
         <child>
-          <widget class="Gtk.HBox" id="hbox1">
-            <property name="MemberName" />
-            <property name="Spacing">6</property>
-            <child>
-              <widget class="Gtk.Entry" id="ip_entry">
-                <property name="MemberName" />
-                <property name="WidthRequest">261</property>
-                <property name="CanFocus">True</property>
-                <property name="Text" translatable="yes">Ip</property>
-                <property name="IsEditable">True</property>
-                <property name="InvisibleChar">●</property>
-              </widget>
-              <packing>
-                <property name="Position">0</property>
-                <property name="AutoSize">False</property>
-                <property name="Expand">False</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="Gtk.Entry" id="port_entry">
-                <property name="MemberName" />
-                <property name="CanFocus">True</property>
-                <property name="Text" translatable="yes">Port</property>
-                <property name="IsEditable">True</property>
-                <property name="InvisibleChar">●</property>
-              </widget>
-              <packing>
-                <property name="Position">1</property>
-                <property name="AutoSize">False</property>
-                <property name="Expand">False</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="Gtk.Button" id="connect_button">
-                <property name="MemberName" />
-                <property name="CanFocus">True</property>
-                <property name="Type">TextOnly</property>
-                <property name="Label" translatable="yes">Connect</property>
-                <property name="UseUnderline">True</property>
-                <signal name="Clicked" handler="OnConnectClicked" />
-              </widget>
-              <packing>
-                <property name="Position">2</property>
-                <property name="AutoSize">True</property>
-                <property name="Expand">False</property>
-                <property name="Fill">False</property>
-              </packing>
-            </child>
-          </widget>
-          <packing>
-            <property name="Position">1</property>
-            <property name="AutoSize">True</property>
-            <property name="Expand">False</property>
-            <property name="Fill">False</property>
-          </packing>
+          <placeholder />
         </child>
         <child>
-          <widget class="Gtk.ScrolledWindow" id="scrolledwindow1">
-            <property name="MemberName" />
-            <property name="CanFocus">True</property>
-            <property name="ShadowType">In</property>
-            <child>
-              <widget class="Gtk.TextView" id="textview1">
-                <property name="MemberName" />
-                <property name="CanFocus">True</property>
-                <property name="Editable">False</property>
-                <property name="Text" translatable="yes" />
-              </widget>
-            </child>
-          </widget>
-          <packing>
-            <property name="Position">2</property>
-            <property name="AutoSize">True</property>
-          </packing>
-        </child>
-        <child>
-          <widget class="Gtk.Entry" id="entry1">
-            <property name="MemberName" />
-            <property name="CanFocus">True</property>
-            <property name="IsEditable">True</property>
-            <property name="InvisibleChar">●</property>
-            <signal name="Activated" handler="OnEntryActivated" />
-            <signal name="KeyPressEvent" handler="OnEntryKeyPressed" />
-          </widget>
-          <packing>
-            <property name="PackType">End</property>
-            <property name="Position">3</property>
-            <property name="AutoSize">True</property>
-            <property name="Expand">False</property>
-            <property name="Fill">False</property>
-          </packing>
+          <placeholder />
         </child>
       </widget>
     </child>

+ 171 - 0
tools/gui/core/ConsoleClient.cs

@@ -0,0 +1,171 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Collections;
+
+namespace Crown
+{
+namespace Core
+{
+	public delegate void MessageReceived(object o, MessageReceivedArgs args);
+	public class MessageReceivedArgs : EventArgs
+	{
+		public readonly string Json;
+		public MessageReceivedArgs(string json)
+		{
+			Json = json;
+		}
+	}
+
+	public delegate void Connected(object o, ConnectedArgs args);
+	public class ConnectedArgs : EventArgs
+	{
+		public readonly string Address;
+		public readonly int Port;
+		public ConnectedArgs(string address, int port)
+		{
+			Address = address;
+			Port = port;
+		}
+	}
+
+	public delegate void Disconnected(object o, DisconnectedArgs args);
+	public class DisconnectedArgs : EventArgs
+	{
+		public DisconnectedArgs()
+		{
+		}
+	}
+
+	// Manages communication with engine executable.
+	public class ConsoleClient
+	{
+		private Socket Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+
+		// Events
+		public event Connected ConnectedEvent;
+		public event Disconnected DisconnectedEvent;
+		public event MessageReceived MessageReceivedEvent;
+
+		public void Connect(string address, int port)
+		{
+			try {
+				Client.BeginConnect(new IPEndPoint(IPAddress.Parse(address), port), new AsyncCallback(OnConnected), Client);
+			}
+			catch (Exception e) {
+				Console.WriteLine(e.ToString());
+			}
+		}
+
+		public void Close()
+		{
+			try {
+				if (Client.Connected) {
+					Client.Shutdown(SocketShutdown.Both);
+					Client.Close();
+					EmitDisconnected();
+				}
+			}
+			catch (Exception e) {
+				Console.WriteLine(e.ToString());
+			}
+		}
+
+		private void OnConnected(IAsyncResult ar)
+		{
+			try {
+				Socket client = (Socket)ar.AsyncState;
+				client.EndConnect(ar);
+				IPEndPoint ep = client.RemoteEndPoint as IPEndPoint;
+				EmitConnected(ep.Address.ToString(), ep.Port);
+				Receive(client);
+			}
+			catch (Exception e) {
+				Console.WriteLine(e.ToString());
+			}
+		}
+
+		// Sends the JSON-encoded data to the target
+		public void Send(string json)
+		{
+			try {
+				Client.Send(BitConverter.GetBytes(json.Length));
+				Client.Send(Encoding.ASCII.GetBytes(json));
+			} catch (Exception e) {
+				Console.WriteLine(e.ToString());
+			}
+		}
+
+		// Sends the lua script to the target
+		public void SendScript(string lua)
+		{
+			lua = lua.Replace("\"", "\\\"");
+			string json = "{\"type\":\"script\",\"script\":\"" + lua + "\"}";
+			Send(json);
+		}
+
+		private class StateObject
+		{
+			public Socket Client;
+			public byte[] msgHeader = new byte[4];
+			public byte[] buf = new byte[4096];
+		}
+
+		private void Receive(Socket client)
+		{
+			try {
+				StateObject state = new StateObject();
+				state.Client = client;
+				Client.BeginReceive(state.msgHeader, 0, 4, SocketFlags.None, new AsyncCallback(OnReceive), state);
+			}
+			catch (Exception e) {
+				Console.WriteLine(e.ToString());
+			}
+		}
+
+		private void OnReceive(IAsyncResult ar)
+		{
+			try {
+				StateObject state = (StateObject)ar.AsyncState;
+				Socket client = state.Client;
+
+				int bytesRead = client.EndReceive(ar);
+				if(bytesRead > 0)
+				{
+					Int32 size = BitConverter.ToInt32(state.msgHeader, 0);
+					int rr = client.Receive(state.buf, size, SocketFlags.None);
+					string json = Encoding.ASCII.GetString(state.buf, 0, rr);
+					EmitMessageReceived(json);
+					Receive(client);
+				}
+				else
+				{
+					Close();
+				}
+			}
+			catch(Exception e) {
+				Console.WriteLine(e.ToString());
+			}
+		}
+
+		public void EmitDisconnected()
+		{
+			if (DisconnectedEvent != null)
+				DisconnectedEvent(this, new DisconnectedArgs());
+		}
+
+		public void EmitMessageReceived(string json)
+		{
+			if (MessageReceivedEvent != null)
+				MessageReceivedEvent(this, new MessageReceivedArgs(json));
+		}
+
+		public void EmitConnected(string address, int port)
+		{
+			if (ConnectedEvent != null)
+				ConnectedEvent(this, new ConnectedArgs(address, port));
+		}
+	}
+} // namespace Core
+} // namespace Crown

+ 27 - 0
tools/gui/core/Properties/AssemblyInfo.cs

@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("core")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("dani")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+

+ 37 - 0
tools/gui/core/core.csproj

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{B26EAA66-08A9-493F-9C9F-85F7F5C57304}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>core</RootNamespace>
+    <AssemblyName>core</AssemblyName>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>full</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ConsoleClient.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project>

+ 15 - 13
tools/gui/toolbox.sln

@@ -7,7 +7,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "console", "console\console.
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "crown-tests", "crown-tests\crown-tests.csproj", "{4E5F6C4E-8C96-4903-B6AE-5C9ADCFC2C20}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "world-editor", "world-editor\world-editor.csproj", "{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "core", "core\core.csproj", "{B26EAA66-08A9-493F-9C9F-85F7F5C57304}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -20,6 +20,7 @@ Global
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 		{1307AAA0-BFB8-494C-83CB-A4171C2E87F1}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{1307AAA0-BFB8-494C-83CB-A4171C2E87F1}.Debug|Any CPU.Build.0 = Debug|x86
 		{1307AAA0-BFB8-494C-83CB-A4171C2E87F1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
 		{1307AAA0-BFB8-494C-83CB-A4171C2E87F1}.Debug|Mixed Platforms.Build.0 = Debug|x86
 		{1307AAA0-BFB8-494C-83CB-A4171C2E87F1}.Debug|x86.ActiveCfg = Debug|x86
@@ -40,6 +41,7 @@ Global
 		{4E5F6C4E-8C96-4903-B6AE-5C9ADCFC2C20}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{4E5F6C4E-8C96-4903-B6AE-5C9ADCFC2C20}.Release|x86.ActiveCfg = Release|Any CPU
 		{7FF1E014-7560-481E-B919-080C42F4C6EC}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{7FF1E014-7560-481E-B919-080C42F4C6EC}.Debug|Any CPU.Build.0 = Debug|x86
 		{7FF1E014-7560-481E-B919-080C42F4C6EC}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
 		{7FF1E014-7560-481E-B919-080C42F4C6EC}.Debug|Mixed Platforms.Build.0 = Debug|x86
 		{7FF1E014-7560-481E-B919-080C42F4C6EC}.Debug|x86.ActiveCfg = Debug|x86
@@ -49,18 +51,18 @@ Global
 		{7FF1E014-7560-481E-B919-080C42F4C6EC}.Release|Mixed Platforms.Build.0 = Release|x86
 		{7FF1E014-7560-481E-B919-080C42F4C6EC}.Release|x86.ActiveCfg = Release|x86
 		{7FF1E014-7560-481E-B919-080C42F4C6EC}.Release|x86.Build.0 = Release|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Debug|Any CPU.ActiveCfg = Debug|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Debug|Any CPU.Build.0 = Debug|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Debug|Mixed Platforms.Build.0 = Debug|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Debug|x86.ActiveCfg = Debug|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Debug|x86.Build.0 = Debug|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Release|Any CPU.ActiveCfg = Release|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Release|Any CPU.Build.0 = Release|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Release|Mixed Platforms.ActiveCfg = Release|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Release|Mixed Platforms.Build.0 = Release|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Release|x86.ActiveCfg = Release|x86
-		{8B9CA77F-30BD-433E-BB35-6E8618BE9EEB}.Release|x86.Build.0 = Release|x86
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Debug|x86.Build.0 = Debug|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Release|x86.ActiveCfg = Release|Any CPU
+		{B26EAA66-08A9-493F-9C9F-85F7F5C57304}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(MonoDevelopProperties) = preSolution
 		StartupItem = console\console.csproj