From d828af7036fd11a4a1f678b2b7e51bdb6380087a Mon Sep 17 00:00:00 2001
From: gareth
Date: Tue, 6 Mar 2007 15:57:36 +0000
Subject: Implemented local console and VERY rough skeleton for TCP/Worldchat
 console Implemented seperate logging (but no packetlog or chat yet)

---
 opensim.build              |   1 +
 src/Config.cs              | 107 ++++++++-----------------
 src/Main.cs                |  49 ++++++++----
 src/OpenSimClient.cs       |  45 ++++++-----
 src/ServerConsole.cs       | 190 +++++++++++++++++++++++++++++++++++++++++++++
 src/world/Avatar.cs        |  15 ++--
 src/world/PhysicsEngine.cs |   2 +-
 src/world/World.cs         |  12 +--
 8 files changed, 293 insertions(+), 128 deletions(-)
 create mode 100644 src/ServerConsole.cs

diff --git a/opensim.build b/opensim.build
index e2bf633..2fdf1cb 100644
--- a/opensim.build
+++ b/opensim.build
@@ -49,6 +49,7 @@
 			</references>
 			<sources basedir="src/">
         	        	<include name="AssemblyInfo.cs" />
+				<include name="ServerConsole.cs" />
 				<include name="Config.cs" />
 				<include name="VersionInfo.cs" />
 				<include name="Util.cs" />
diff --git a/src/Config.cs b/src/Config.cs
index dc01df9..55bcdfe 100644
--- a/src/Config.cs
+++ b/src/Config.cs
@@ -64,68 +64,27 @@ namespace OpenSim
 		
 		public void LoadDefaults() {
 			string tempstring;
-			Console.WriteLine("Config.cs:LoadDefaults() - Please press enter to retain default or enter new settings");
-			Console.Write("Name [OpenSim test]:");
-			tempstring=Console.ReadLine();
-			if(tempstring=="") {
-				this.RegionName = "OpenSim test";
-			} else {
-				this.RegionName = tempstring;
-			}
-
-			Console.Write("Grid location X [997]:");
-			tempstring=Console.ReadLine();
-			if(tempstring=="") {
-				this.RegionLocX = 997;
-			} else {
-				this.RegionLocX = (uint)Convert.ToInt32(tempstring);
-			}
-		
-			Console.Write("Grid location Y [996]:");
-			tempstring=Console.ReadLine();
-			if(tempstring=="") {
-				this.RegionLocY = 996;
-			} else {
-				this.RegionLocY = (uint)Convert.ToInt32(tempstring);
-			}
-
-			Console.Write("Listen on UDP port for client connections [9000]:");
-			tempstring=Console.ReadLine();
-                        if(tempstring=="") {
-                                this.IPListenPort = 9000;
-                        } else {
-                                this.IPListenPort = Convert.ToInt32(tempstring);
-                        }
-
-			Console.Write("Listen on IP address for client connections [127.0.0.1]:");
-			tempstring=Console.ReadLine();
-			if(tempstring=="") {
-                                this.IPListenAddr = "127.0.0.1";
-                        } else {
-                                this.IPListenAddr = tempstring;
-                        }
+			OpenSim_Main.localcons.WriteLine("Config.cs:LoadDefaults() - Please press enter to retain default or enter new settings");
+			
+			this.RegionName=OpenSim_Main.localcons.CmdPrompt("Name [OpenSim test]: ","OpenSim test");
+			this.RegionLocX=(uint)Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("Grid Location X [997]: ","997"));
+			this.RegionLocY=(uint)Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("Grid Location Y [996]: ","996"));
+			this.IPListenPort=Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("UDP port for client connections [9000]: ","9000"));
+			this.IPListenAddr=OpenSim_Main.localcons.CmdPrompt("IP Address to listen on for client connections [127.0.0.1]: ","127.0.0.1");
 	
 	
-			Console.Write("Run in sandbox or grid mode? [sandbox]:");
-			tempstring=Console.ReadLine();
-			if(tempstring=="") {
-                                this.sandbox = true;
-                        } else if(tempstring=="grid"){
+			tempstring=OpenSim_Main.localcons.CmdPrompt("Run in sandbox or grid mode? [sandbox]: ","sandbox", "sandbox", "grid");
+                        if(tempstring=="grid"){
                                 this.sandbox = false;
                         } else if(tempstring=="sandbox"){
 				this.sandbox=true;
 			}
 
 			if(!this.sandbox) {
-				Console.Write("Asset server URL:");
-				this.AssetURL=Console.ReadLine();
-				Console.Write("Key to send to asset server:");
-				this.AssetSendKey=Console.ReadLine();
-				Console.Write("Grid server URL:");
-				this.GridURL=Console.ReadLine();
-				Console.Write("Key to send to gridserver:");
-				this.GridSendKey=Console.ReadLine();
-				
+				this.AssetURL=OpenSim_Main.localcons.CmdPrompt("Asset server URL: ");
+				this.AssetSendKey=OpenSim_Main.localcons.CmdPrompt("Asset server key: ");
+				this.GridURL=OpenSim_Main.localcons.CmdPrompt("Grid server URL: ");
+				this.GridSendKey=OpenSim_Main.localcons.CmdPrompt("Grid server key: ");
 			}
 			this.RegionHandle = Helpers.UIntsToLong((RegionLocX*256), (RegionLocY*256));
 		}
@@ -135,7 +94,7 @@ namespace OpenSim
 				db = Db4oFactory.OpenFile("opensim.yap");
 				IObjectSet result = db.Get(typeof(SimConfig));
 				if(result.Count==1) {
-					Console.WriteLine("Config.cs:InitConfig() - Found a SimConfig object in the local database, loading");
+					OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Found a SimConfig object in the local database, loading");
 					foreach (SimConfig cfg in result) {
 						this.RegionName = cfg.RegionName;
 						this.RegionLocX = cfg.RegionLocX;
@@ -149,38 +108,38 @@ namespace OpenSim
 						this.GridSendKey = cfg.GridSendKey;
 					}
 				} else {
-					Console.WriteLine("Config.cs:InitConfig() - Could not find object in database, loading precompiled defaults");
+					OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Could not find object in database, loading precompiled defaults");
 					LoadDefaults();
-					Console.WriteLine("Writing out default settings to local database");
+					OpenSim_Main.localcons.WriteLine("Writing out default settings to local database");
 					db.Set(this);
 				}
 			} catch(Exception e) {
 				db.Close();
-				Console.WriteLine("Config.cs:InitConfig() - Exception occured");
-				Console.WriteLine(e.ToString());
+				OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Exception occured");
+				OpenSim_Main.localcons.WriteLine(e.ToString());
 			}
-			Console.WriteLine("Sim settings loaded:");
-			Console.WriteLine("Name: " + this.RegionName);
-			Console.WriteLine("Region Location: [" + this.RegionLocX.ToString() + "," + this.RegionLocY + "]");
-			Console.WriteLine("Region Handle: " + this.RegionHandle.ToString());
-			Console.WriteLine("Listening on IP: " + this.IPListenAddr + ":" + this.IPListenPort);
-			Console.WriteLine("Sandbox Mode? " + this.sandbox.ToString());
-			Console.WriteLine("Asset URL: " + this.AssetURL);
-			Console.WriteLine("Asset key: " + this.AssetSendKey);
-			Console.WriteLine("Grid URL: " + this.GridURL);
-			Console.WriteLine("Grid key: " + this.GridSendKey);
+			OpenSim_Main.localcons.WriteLine("Sim settings loaded:");
+			OpenSim_Main.localcons.WriteLine("Name: " + this.RegionName);
+			OpenSim_Main.localcons.WriteLine("Region Location: [" + this.RegionLocX.ToString() + "," + this.RegionLocY + "]");
+			OpenSim_Main.localcons.WriteLine("Region Handle: " + this.RegionHandle.ToString());
+			OpenSim_Main.localcons.WriteLine("Listening on IP: " + this.IPListenAddr + ":" + this.IPListenPort);
+			OpenSim_Main.localcons.WriteLine("Sandbox Mode? " + this.sandbox.ToString());
+			OpenSim_Main.localcons.WriteLine("Asset URL: " + this.AssetURL);
+			OpenSim_Main.localcons.WriteLine("Asset key: " + this.AssetSendKey);
+			OpenSim_Main.localcons.WriteLine("Grid URL: " + this.GridURL);
+			OpenSim_Main.localcons.WriteLine("Grid key: " + this.GridSendKey);
 		}
 	
 		public World LoadWorld() {
-			Console.WriteLine("Config.cs:LoadWorld() - Looking for a world object in local DB");
+			OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Looking for a world object in local DB");
 	//		IObjectSet world_result = db.Get(typeof(OpenSim.world.World));
 	//		if(world_result.Count==1) {
-	//			Console.WriteLine("Config.cs:LoadWorld() - Found an OpenSim.world.World object in local database, loading");
+	//			OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Found an OpenSim.world.World object in local database, loading");
 				//return (World)world_result.Next();	
 	//		} else {
-				Console.WriteLine("Config.cs:LoadWorld() - Could not find the world or too many worlds! Constructing blank one");
+				OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Could not find the world or too many worlds! Constructing blank one");
 				World blank = new World();
-				Console.WriteLine("Config.cs:LoadWorld() - Saving initial world state to disk");
+				OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Saving initial world state to disk");
 				//db.Set(blank);
 				//db.Commit();
 				return blank;	
@@ -188,7 +147,7 @@ namespace OpenSim
 		}
 
 		public void LoadFromGrid() {
-			Console.WriteLine("Config.cs:LoadFromGrid() - dummy function, DOING ABSOLUTELY NOTHING AT ALL!!!");
+			OpenSim_Main.localcons.WriteLine("Config.cs:LoadFromGrid() - dummy function, DOING ABSOLUTELY NOTHING AT ALL!!!");
 			// TODO: Make this crap work
 		}
 
diff --git a/src/Main.cs b/src/Main.cs
index fe2183b..f3fa609 100644
--- a/src/Main.cs
+++ b/src/Main.cs
@@ -46,9 +46,11 @@ namespace OpenSim
     /// </summary>
     public class OpenSim_Main 
     {
+	public static DateTime startuptime;
 	public static OpenSim_Main sim;
 	public static SimConfig cfg;
 	public static World local_world;
+	public static ServerConsole localcons;
 	private static Thread MainListener;
 	public static Socket Server;
 	private static IPEndPoint ServerIncoming;
@@ -67,32 +69,49 @@ namespace OpenSim
 		sim = new OpenSim_Main();		
 		sim.Startup();
 		while(true) {
-			local_world.DoStuff();
-			Thread.Sleep(100);
+			localcons.MainConsolePrompt();
 		}
 	}
 
 	private OpenSim_Main() {
 	}
 	
+	public static void Shutdown() {
+		localcons.WriteLine("Main.cs:Shutdown() - Closing all threads");
+		localcons.WriteLine("Main.cs:Shutdown() - Killing listener thread");
+		MainListener.Abort();
+		localcons.WriteLine("Main.cs:Shutdown() - Killing clients");
+		// IMPLEMENT THIS
+		localcons.WriteLine("Main.cs:Shutdown() - Closing console and terminating");
+		localcons.Close();
+		Environment.Exit(0);
+	}
+
 	private void Startup() {
+		startuptime=DateTime.Now;
+		localcons=new ServerConsole(ServerConsole.ConsoleType.Local,"",0);
 		// We check our local database first, then the grid for config options
-		Console.WriteLine("Main.cs:Startup() - Loading configuration");
+		localcons.WriteLine("Main.cs:Startup() - Loading configuration");
 		cfg = new SimConfig();
 		cfg.InitConfig();
-		Console.WriteLine("Main.cs:Startup() - Contacting gridserver");
+		localcons.WriteLine("Main.cs:Startup() - Contacting gridserver");
 		cfg.LoadFromGrid();
 
-		Console.WriteLine("Main.cs:Startup() - We are " + cfg.RegionName + " at " + cfg.RegionLocX.ToString() + "," + cfg.RegionLocY.ToString());
-		Console.WriteLine("Initialising world");
+		localcons.WriteLine("Main.cs:Startup() - We are " + cfg.RegionName + " at " + cfg.RegionLocX.ToString() + "," + cfg.RegionLocY.ToString());
+		localcons.WriteLine("Initialising world");
 		local_world = cfg.LoadWorld();
 
-		Console.WriteLine("Main.cs:Startup() - Starting up messaging system");
+		localcons.WriteLine("Main.cs:Startup() - Starting up main world loop");
+                local_world.InitLoop();
+
+		localcons.WriteLine("Main.cs:Startup() - Starting up messaging system");
 		MainListener = new Thread(new ThreadStart(MainServerListener));	
 		MainListener.Start();
 
-		Console.WriteLine("Main.cs:Startup() - Starting up main world loop");
-		local_world.InitLoop();
+		Thread.Sleep(500); // give other threads a chance to catch up
+		string[] noparams = new string[1];
+		noparams[0]="";
+		localcons.WriteLine("\nOpenSim ready\nType help for list of commands");
 	}
 
 	private void OnReceivedData(IAsyncResult result) {
@@ -102,7 +121,6 @@ namespace OpenSim
 		int numBytes = Server.EndReceiveFrom(result, ref epSender);
 		int packetEnd = numBytes - 1;
 		packet = Packet.BuildPacket(RecvBuffer, ref packetEnd, ZeroBuffer);
-		Console.Error.WriteLine(packet.ToString());
 
 		// This is either a new client or a packet to send to an old one
 		if(ClientThreads.ContainsKey(epSender)) {
@@ -117,23 +135,24 @@ namespace OpenSim
 	}
 
 	private void MainServerListener() {
-		Console.WriteLine("Main.cs:MainServerListener() - New thread started");
-		Console.WriteLine("Main.cs:MainServerListener() - Opening UDP socket on " + cfg.IPListenAddr + ":" + cfg.IPListenPort);
+		localcons.WriteLine("Main.cs:MainServerListener() - New thread started");
+		localcons.WriteLine("Main.cs:MainServerListener() - Opening UDP socket on " + cfg.IPListenAddr + ":" + cfg.IPListenPort);
 
         ServerIncoming = new IPEndPoint(IPAddress.Any, cfg.IPListenPort);
 		Server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
 		Server.Bind(ServerIncoming);
 		
-		Console.WriteLine("Main.cs:MainServerListener() - UDP socket bound, getting ready to listen");
+		localcons.WriteLine("Main.cs:MainServerListener() - UDP socket bound, getting ready to listen");
 
 		ipeSender = new IPEndPoint(IPAddress.Any, 0);
 		epSender = (EndPoint) ipeSender;
 		ReceivedData = new AsyncCallback(this.OnReceivedData);
 		Server.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null);
 		
-		Console.WriteLine("Main.cs:MainServerListener() - Listening...");
+		localcons.WriteLine("Main.cs:MainServerListener() - Listening...");
 		while(true) {
-			Thread.Sleep(1000);	
+			Thread.Sleep(100);
+			local_world.DoStuff();
 		}
 	}
     }
diff --git a/src/OpenSimClient.cs b/src/OpenSimClient.cs
index 6b00a0f..0e956c3 100644
--- a/src/OpenSimClient.cs
+++ b/src/OpenSimClient.cs
@@ -49,7 +49,7 @@ namespace OpenSim
 		public world.Avatar ClientAvatar;
 		private UseCircuitCodePacket cirpack;
 		private Thread ClientThread;
-		private EndPoint userEP;
+		public EndPoint userEP;
 		private  BlockingQueue<QueItem> PacketQueue;
 		private BlockingQueue<TransferRequestPacket> AssetRequests;
 		private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
@@ -81,9 +81,9 @@ namespace OpenSim
 		
 		public void AssetLoader() {
 			if(OpenSim_Main.cfg.sandbox==false) {
-			Console.WriteLine("OpenSimClient.cs:AssetLoader() - Starting new thread");
+			OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Starting new thread");
 			TransferRequestPacket reqPacket = AssetRequests.Dequeue();
-			Console.WriteLine("OpenSimClient.cs:AssetLoader() - Got a request, processing it");
+			OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Got a request, processing it");
 			LLUUID AssetID = new LLUUID(reqPacket.TransferInfo.Params, 0);
 			WebRequest AssetLoad = WebRequest.Create(OpenSim_Main.cfg.AssetURL + "getasset/" + OpenSim_Main.cfg.AssetSendKey + "/" + AssetID + "/data");
 			WebResponse AssetResponse = AssetLoad.GetResponse();
@@ -131,7 +131,12 @@ namespace OpenSim
 			AssetResponse.Close();
 			}
 		}
-		
+	
+		public void Logout() {
+			// TODO - kill any AssetLoaders
+			ClientThread.Abort();
+		}
+	
 		public void ProcessInPacket(Packet Pack) {
 		    ack_pack(Pack);
 		    switch(Pack.Type) {
@@ -146,7 +151,7 @@ namespace OpenSim
 				ClientAvatar.SendInitialAppearance();
 			break;
 			case PacketType.TransferRequest:
-				Console.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got transfer request");
+				OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got transfer request");
 				// We put transfer requests into a big queue and then spawn a thread for each new one
 				TransferRequestPacket transfer = (TransferRequestPacket)Pack;
 		    		AssetRequests.Enqueue(transfer);
@@ -154,7 +159,7 @@ namespace OpenSim
                         	AssetLoaderThread.Start();
 			break;
 			case PacketType.LogoutRequest:
-				Console.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got a logout request");
+				OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got a logout request");
 				lock(OpenSim_Main.local_world.Entities) {
 					OpenSim_Main.local_world.Entities.Remove(this.AgentID);	
 				}
@@ -166,7 +171,7 @@ namespace OpenSim
                         	String grTest = sr.ReadLine();
                         	sr.Close();
 	                        GridResponse.Close();
-				Console.WriteLine("DEBUG: " + grTest);
+				OpenSim_Main.localcons.WriteLine("DEBUG: " + grTest);
 				}
 				this.ClientThread.Abort();
 			break;
@@ -207,8 +212,6 @@ namespace OpenSim
 	 				{
 	 					if (now - packet.TickCount > RESEND_TIMEOUT)
 	 					{
-	 						Console.WriteLine("Resending " + packet.Type.ToString() + " packet, " +
-	 						 (now - packet.TickCount) + "ms have passed", Helpers.LogLevel.Info);
 
 	 						packet.Header.Resent = true;
 	 						OutPacket(packet);
@@ -225,12 +228,10 @@ namespace OpenSim
 	 			{
 	 				if (PendingAcks.Count > 250)
 	 				{
-	 					// FIXME: Handle the odd case where we have too many pending ACKs queued up
-	 					Console.WriteLine("Too many ACKs queued up!", Helpers.LogLevel.Error);
 	 					return;
 	 				}
 					
-					Console.WriteLine("Sending PacketAck");
+					OpenSim_Main.localcons.WriteLine("Sending PacketAck");
 					
 
 	 				int i = 0;
@@ -319,7 +320,6 @@ namespace OpenSim
 	 				}
 	 			}
 
-		Console.WriteLine("OUT: \n" + Pack.ToString());
 
 		    byte[] ZeroOutBuffer = new byte[4096];
 		    byte[] sendbuffer; 
@@ -333,7 +333,7 @@ namespace OpenSim
 				OpenSim_Main.Server.SendTo(sendbuffer, sendbuffer.Length, SocketFlags.None,userEP);
 			}
 		    } catch (Exception) {
-			Console.WriteLine("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread");
+			OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread");
 			ClientThread.Abort();
 		    }
 	
@@ -347,7 +347,7 @@ namespace OpenSim
 	 			{
 	 				foreach (uint ack in NewPack.Header.AckList)
 	 				{
-						Console.WriteLine("Got appended ack: "+ack);
+						OpenSim_Main.localcons.WriteLine("Got appended ack: "+ack);
 	 					NeedAck.Remove(ack);
 	 				}
 	 			}
@@ -362,7 +362,6 @@ namespace OpenSim
 	 			{
 	 				foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
 	 				{
-						Console.WriteLine("Got PacketAck: "+block.ID);
 	 					NeedAck.Remove(block.ID);
 	 				}
 	 			}
@@ -391,7 +390,7 @@ namespace OpenSim
 		}
 
 		public OpenSimClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack) {
-	                Console.WriteLine("OpenSimClient.cs - Started up new client thread to handle incoming request");
+	                OpenSim_Main.localcons.WriteLine("OpenSimClient.cs - Started up new client thread to handle incoming request");
 			cirpack = initialcirpack;
 			userEP = remoteEP;
 			PacketQueue = new BlockingQueue<QueItem>();
@@ -406,7 +405,7 @@ namespace OpenSim
 		}
 		
 		private void ClientLoop() {
-			Console.WriteLine("OpenSimClient.cs:ClientLoop() - Entered loop");
+			OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ClientLoop() - Entered loop");
 			while(true) {
 				QueItem nextPacket = PacketQueue.Dequeue();
 				if(nextPacket.Incoming)
@@ -423,7 +422,7 @@ namespace OpenSim
 		}
 
 		private void InitNewClient() {
-			Console.WriteLine("OpenSimClient.cs:InitNewClient() - Adding viewer agent to world");
+			OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:InitNewClient() - Adding viewer agent to world");
 			OpenSim_Main.local_world.AddViewerAgent(this);
 			world.Entity tempent=OpenSim_Main.local_world.Entities[this.AgentID];
 			this.ClientAvatar=(world.Avatar)tempent;
@@ -431,23 +430,23 @@ namespace OpenSim
 		
 		private void AuthUser() {
 			if(OpenSim_Main.cfg.sandbox==false) {
-				Console.WriteLine("OpenSimClient.cs:AuthUser() - Authenticating new user request with grid");
+				OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Authenticating new user request with grid");
 				WebRequest CheckSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + cirpack.CircuitCode.ID.ToString() + "/" + cirpack.CircuitCode.Code.ToString() + "/exists");
-				Console.WriteLine(OpenSim_Main.cfg.GridURL);
+				OpenSim_Main.localcons.WriteLine(OpenSim_Main.cfg.GridURL);
 				WebResponse GridResponse = CheckSession.GetResponse();
 				StreamReader sr = new StreamReader(GridResponse.GetResponseStream());
 				String grTest = sr.ReadLine();
 				sr.Close();
 				GridResponse.Close();
 				if(String.IsNullOrEmpty(grTest) || grTest.Equals("1")) { 	// YAY! Valid login
-					Console.WriteLine("OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString());
+					OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString());
 					this.AgentID=cirpack.CircuitCode.ID;
 					this.SessionID=cirpack.CircuitCode.SessionID;
 					this.CircuitCode=cirpack.CircuitCode.Code;
 					InitNewClient();
 					ClientLoop();	
 				} else {			// Invalid
-					Console.WriteLine("OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString());
+					OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString());
 					ClientThread.Abort();	
 				}
 			} else {
diff --git a/src/ServerConsole.cs b/src/ServerConsole.cs
new file mode 100644
index 0000000..690e8ee
--- /dev/null
+++ b/src/ServerConsole.cs
@@ -0,0 +1,190 @@
+/*
+Copyright (c) OpenSim project, http://osgrid.org/
+
+* Copyright (c) <year>, <copyright holder>
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the <organization> nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+using System.IO;
+using System.Net;
+using libsecondlife;
+using libsecondlife.Packets;
+
+namespace OpenSim
+{
+	public class ServerConsole {
+		private ConsoleType ConsType;
+		StreamWriter Log;
+		
+		public enum ConsoleType {
+			Local,		// Use stdio
+			TCP,		// Use TCP/telnet
+			SimChat		// Use in-world chat (for gods)
+		}
+
+		
+		// STUPID HACK ALERT!!!! STUPID HACK ALERT!!!!!
+		// constype - the type of console to use (see enum ConsoleType)
+		// sparam - depending on the console type:
+		//		TCP - the IP to bind to (127.0.0.1 if blank)
+		//		Local - param ignored
+		//		SimChat - the AgentID of this sim's admin
+		// and for the iparam:
+		//		TCP - the port to bind to
+		//		Local - param ignored
+		//		SimChat - the chat channel to accept commands from
+		public ServerConsole(ConsoleType constype, string sparam, int iparam) {
+			ConsType = constype;
+			switch(constype) {
+				case ConsoleType.Local:
+				Console.WriteLine("ServerConsole.cs - creating new local console");
+				Console.WriteLine("Logs will be saved to current directory in opensim-console.log");
+				Log=File.AppendText("opensim-console.log");
+				Log.WriteLine("========================================================================");
+				Log.WriteLine("OpenSim " + VersionInfo.Version + " Started at " + DateTime.Now.ToString());
+				break;
+				case ConsoleType.TCP:
+				break;
+				case ConsoleType.SimChat:
+				break;
+				
+				default:
+					Console.WriteLine("ServerConsole.cs - what are you smoking? that isn't a valid console type!");
+				break;
+			}
+		}
+
+		public void Close() {
+			Log.WriteLine("OpenSim shutdown at " + DateTime.Now.ToString());
+			Log.Close();
+		}
+	
+		// You know what ReadLine() and WriteLine() do, right? And Read() and Write()? Right, you do actually know C#, right? Are you actually a programmer? Do you know english? Do you find my sense of humour in comments irritating? Good, glad you're still here
+		public void WriteLine(string Line) {
+			Log.WriteLine(Line);
+			Console.WriteLine(Line);
+			return;
+		}
+		
+		public string ReadLine() {
+			string TempStr=Console.ReadLine();
+			Log.WriteLine(TempStr);
+			return TempStr;
+		}
+
+		public int Read() {
+			int TempInt= Console.Read();
+			Log.Write((char)TempInt);
+			return TempInt;
+		}
+
+		public void Write(string Line) {
+			Console.Write(Line);
+			Log.Write(Line);
+			return;
+		}
+
+		// Displays a command prompt and waits for the user to enter a string, then returns that string
+		public string CmdPrompt(string prompt) {
+			this.Write(prompt);
+			return this.ReadLine();
+		}
+
+		// Displays a command prompt and returns a default value if the user simply presses enter
+		public string CmdPrompt(string prompt, string defaultresponse) {
+			string temp=CmdPrompt(prompt);
+			if(temp=="") {
+				 return defaultresponse;
+			} else {
+				return temp;
+			}
+		}
+
+		// Displays a command prompt and returns a default value, user may only enter 1 of 2 options
+		public string CmdPrompt(string prompt, string defaultresponse, string OptionA, string OptionB) {
+			bool itisdone=false;
+			string temp=CmdPrompt(prompt,defaultresponse);
+			while(itisdone==false) {
+				if((temp==OptionA) || (temp==OptionB)) {
+					itisdone=true;
+				} else {
+					this.WriteLine("Valid options are " + OptionA + " or " + OptionB);
+					temp=CmdPrompt(prompt,defaultresponse);
+				}
+			}
+			return temp;
+		}
+
+		// Runs a command with a number of parameters
+		public Object RunCmd(string Cmd, string[] cmdparams) {
+			switch(Cmd) {
+				case "show":
+				ShowCommands(cmdparams[0]);
+				break;
+				
+				case "shutdown":
+				OpenSim_Main.Shutdown();
+				break;
+			}
+			return null;
+		}
+
+		// Shows data about something
+		public void ShowCommands(string ShowWhat) {
+			switch(ShowWhat) {
+                                case "uptime":
+				this.WriteLine("OpenSim has been running since " + OpenSim_Main.startuptime.ToString());
+                                this.WriteLine("That is " + (DateTime.Now-OpenSim_Main.startuptime).ToString());
+				break;
+				case "users":
+				OpenSim.world.Avatar TempAv;
+				this.WriteLine(String.Format("{0,-16}{1,-16}{2,-25}{3,-25}{4,-16},{5,-16}","Firstname", "Lastname","Agent ID", "Session ID", "Circuit", "IP"));
+				foreach (libsecondlife.LLUUID UUID in OpenSim_Main.local_world.Entities.Keys) {
+					TempAv=(OpenSim.world.Avatar)OpenSim_Main.local_world.Entities[UUID];
+					this.WriteLine(String.Format("{0,-16}{1,-16}{2,-25}{3,-25}{4,-16},{5,-16}",TempAv.firstname, TempAv.lastname,UUID, TempAv.ControllingClient.SessionID, TempAv.ControllingClient.CircuitCode, TempAv.ControllingClient.userEP.ToString()));
+				}
+				break;
+			}
+		}
+	
+		// Displays a prompt to the user and then runs the command they entered
+		public void MainConsolePrompt() {
+			string[] tempstrarray;
+			string tempstr = this.CmdPrompt("OpenSim-" + OpenSim_Main.cfg.RegionHandle.ToString() + " # ");
+			tempstrarray = tempstr.Split(' ');
+			string cmd=tempstrarray[0];
+			Array.Reverse(tempstrarray);
+			Array.Resize<string>(ref tempstrarray,tempstrarray.Length-1);
+			Array.Reverse(tempstrarray);
+			string[] cmdparams=(string[])tempstrarray;
+			RunCmd(cmd,cmdparams);
+		}
+	}
+
+}
diff --git a/src/world/Avatar.cs b/src/world/Avatar.cs
index 6dcc1dd..26b2002 100644
--- a/src/world/Avatar.cs
+++ b/src/world/Avatar.cs
@@ -21,7 +21,7 @@ namespace OpenSim.world
 	private libsecondlife.Packets.ObjectUpdatePacket.ObjectDataBlock AvatarTemplate;
 
         public Avatar(OpenSimClient TheClient) {
-        	Console.WriteLine("Avatar.cs - Loading details from grid (DUMMY)");
+        	OpenSim_Main.localcons.WriteLine("Avatar.cs - Loading details from grid (DUMMY)");
 		ControllingClient=TheClient;
 		SetupTemplate("avatar-template.dat");
 
@@ -32,8 +32,6 @@ namespace OpenSim.world
 		lock(this) {
 			base.update();
 
-			Console.WriteLine("KeyMask: " + this.CurrentKeyMask);
-	
 			oldvel=this.velocity;
 			oldpos=this.position;
 			if((this.CurrentKeyMask & (uint)MainAvatar.AgentUpdateFlags.AGENT_CONTROL_AT_POS) != 0) {
@@ -42,7 +40,6 @@ namespace OpenSim.world
 				this.velocity.X = tmpVelocity.x;
 				this.velocity.Y = tmpVelocity.y;
 				this.velocity.Z = tmpVelocity.z;
-				Console.WriteLine("Walking at "+ this.velocity.ToString());
 				this.walking=true;
 			} else {
 				this.velocity.X=0;
@@ -82,7 +79,7 @@ namespace OpenSim.world
 		}
 
 	public void CompleteMovement(World RegionInfo) {
-		Console.WriteLine("Avatar.cs:CompleteMovement() - Constructing AgentMovementComplete packet");
+		OpenSim_Main.localcons.WriteLine("Avatar.cs:CompleteMovement() - Constructing AgentMovementComplete packet");
 		AgentMovementCompletePacket mov = new AgentMovementCompletePacket();
 		mov.AgentData.SessionID = this.ControllingClient.SessionID;
 		mov.AgentData.AgentID = this.ControllingClient.AgentID;
@@ -92,7 +89,7 @@ namespace OpenSim.world
 		mov.Data.Position = new LLVector3((float)this.position.X, (float)this.position.Y, (float)this.position.Z);
 		mov.Data.LookAt = new LLVector3(0.99f, 0.042f, 0);
 		
-		Console.WriteLine("Sending AgentMovementComplete packet");
+		OpenSim_Main.localcons.WriteLine("Sending AgentMovementComplete packet");
 		ControllingClient.OutPacket(mov);
 	}
 
@@ -213,11 +210,11 @@ namespace OpenSim.world
 	}
 
 	public void SendRegionHandshake(World RegionInfo) {
-		Console.WriteLine("Avatar.cs:SendRegionHandshake() - Creating empty RegionHandshake packet");
+		OpenSim_Main.localcons.WriteLine("Avatar.cs:SendRegionHandshake() - Creating empty RegionHandshake packet");
 		System.Text.Encoding _enc = System.Text.Encoding.ASCII;
 		RegionHandshakePacket handshake = new RegionHandshakePacket();
 		
-		Console.WriteLine("Avatar.cs:SendRegionhandshake() - Filling in RegionHandshake details");
+		OpenSim_Main.localcons.WriteLine("Avatar.cs:SendRegionhandshake() - Filling in RegionHandshake details");
 		handshake.RegionInfo.BillableFactor = 0;
                 handshake.RegionInfo.IsEstateManager = false;
                 handshake.RegionInfo.TerrainHeightRange00 = 60;
@@ -243,7 +240,7 @@ namespace OpenSim.world
                 handshake.RegionInfo.TerrainDetail3 = new LLUUID("00000000-0000-0000-0000-000000000000");
                 handshake.RegionInfo.CacheID = new LLUUID("545ec0a5-5751-1026-8a0b-216e38a7ab37");
 		
-		Console.WriteLine("Avatar.cs:SendRegionHandshake() - Sending RegionHandshake packet");
+		OpenSim_Main.localcons.WriteLine("Avatar.cs:SendRegionHandshake() - Sending RegionHandshake packet");
 		this.ControllingClient.OutPacket(handshake);
 	}
 
diff --git a/src/world/PhysicsEngine.cs b/src/world/PhysicsEngine.cs
index 4abf1f2..b237f5e 100644
--- a/src/world/PhysicsEngine.cs
+++ b/src/world/PhysicsEngine.cs
@@ -14,7 +14,7 @@ namespace OpenSim.world
 	}
 	
 	public void Startup() {
-		Console.WriteLine("PhysicsEngine.cs:Startup() - DOING NOTHING, DUMMY FUNCTION!");
+		OpenSim_Main.localcons.WriteLine("PhysicsEngine.cs:Startup() - DOING NOTHING, DUMMY FUNCTION!");
 	}
  
 	public void DoStuff(World simworld) {
diff --git a/src/world/World.cs b/src/world/World.cs
index f32f9ef..2f73bd5 100644
--- a/src/world/World.cs
+++ b/src/world/World.cs
@@ -20,10 +20,10 @@ namespace OpenSim.world
 
         public World()
         {
-		Console.WriteLine("World.cs - creating new entitities instance");				
+		OpenSim_Main.localcons.WriteLine("World.cs - creating new entitities instance");				
 		Entities = new Dictionary<libsecondlife.LLUUID, Entity>();
 
-		Console.WriteLine("World.cs - creating LandMap");
+		OpenSim_Main.localcons.WriteLine("World.cs - creating LandMap");
 		terrainengine = new TerrainDecode();
                 LandMap = new float[65536];
 		for(int i =0; i < 65536; i++) {
@@ -33,7 +33,7 @@ namespace OpenSim.world
         }
 
 	public void InitLoop() {
-		Console.WriteLine("World.cs:StartLoop() - Initialising physics");
+		OpenSim_Main.localcons.WriteLine("World.cs:StartLoop() - Initialising physics");
 		this.physics = new PhysicsEngine();
 		physics.Startup();
 	}
@@ -76,11 +76,11 @@ namespace OpenSim.world
 	}
 
 	public void AddViewerAgent(OpenSimClient AgentClient) {
-		Console.WriteLine("World.cs:AddViewerAgent() - Creating new avatar for remote viewer agent");
+		OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Creating new avatar for remote viewer agent");
 		Avatar NewAvatar = new Avatar(AgentClient);
-		Console.WriteLine("World.cs:AddViewerAgent() - Adding new avatar to world");
+		OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Adding new avatar to world");
 		this.Entities.Add(AgentClient.AgentID, NewAvatar);
-		Console.WriteLine("World.cs:AddViewerAgent() - Starting RegionHandshake ");
+		OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Starting RegionHandshake ");
 		NewAvatar.SendRegionHandshake(this);
 		this.Update();		// will work for now, but needs to be optimised so we don't update everything in the sim for each new user
 	}
-- 
cgit v1.1