diff --git a/ExtensionLoader/ExtensionLoader.cs b/ExtensionLoader/ExtensionLoader.cs index e0050382..ceb1b772 100644 --- a/ExtensionLoader/ExtensionLoader.cs +++ b/ExtensionLoader/ExtensionLoader.cs @@ -56,6 +56,8 @@ namespace ExtensionLoader /// extensions from /// Object that owns the extensions. A reference to /// this is passed to the constructor of each extension + /// An optional whitelist of extensions to + /// load /// List of assemblies the /// extensions need references to /// Search pattern for extension @@ -67,7 +69,8 @@ namespace ExtensionLoader /// A list of interface references /// to assign extensions to public static void LoadAllExtensions(Assembly assembly, string path, TOwner owner, - List referencedAssemblies, string assemblySearchPattern, string sourceSearchPattern, + List extensionList, List referencedAssemblies, + string assemblySearchPattern, string sourceSearchPattern, object assignablesParent, List assignableInterfaces) { // Add referenced assemblies to the C# compiler @@ -79,12 +82,12 @@ namespace ExtensionLoader } // Load internal extensions - LoadAssemblyExtensions(assembly); + LoadAssemblyExtensions(assembly, extensionList); // Load extensions from external assemblies List extensionNames = ListExtensionAssemblies(path, assemblySearchPattern); foreach (string name in extensionNames) - LoadAssemblyExtensions(Assembly.LoadFile(name)); + LoadAssemblyExtensions(Assembly.LoadFile(name), extensionList); // Load extensions from external code files extensionNames = ListExtensionSourceFiles(path, sourceSearchPattern); @@ -92,7 +95,7 @@ namespace ExtensionLoader { CompilerResults results = CSCompiler.CompileAssemblyFromFile(CSCompilerParams, name); if (results.Errors.Count == 0) - LoadAssemblyExtensions(results.CompiledAssembly); + LoadAssemblyExtensions(results.CompiledAssembly, extensionList); else throw new ExtensionException("Error(s) compiling " + name); } @@ -165,7 +168,7 @@ namespace ExtensionLoader return plugins; } - public static void LoadAssemblyExtensions(Assembly assembly) + public static void LoadAssemblyExtensions(Assembly assembly, List whitelist) { Type[] constructorParams = new Type[] { }; object[] parameters = new object[] { }; @@ -174,7 +177,8 @@ namespace ExtensionLoader { try { - if (t.GetInterface(typeof(IExtension).Name) != null) + if (t.GetInterface(typeof(IExtension).Name) != null && + (whitelist == null || whitelist.Contains(t.Name))) { ConstructorInfo info = t.GetConstructor(constructorParams); IExtension extension = (IExtension)info.Invoke(parameters); diff --git a/ExtensionLoader/Ini/IniDocument.cs b/ExtensionLoader/Ini/IniDocument.cs index 0a996e4d..e7dd0dfc 100644 --- a/ExtensionLoader/Ini/IniDocument.cs +++ b/ExtensionLoader/Ini/IniDocument.cs @@ -247,6 +247,7 @@ namespace ExtensionLoader.Ini // do nothing break; case IniFileType.PythonStyle: + result.AcceptNoAssignmentOperator = false; result.AcceptCommentAfterKey = false; result.SetCommentDelimiters (new char[] { ';', '#' }); result.SetAssignDelimiters (new char[] { ':' }); diff --git a/ExtensionLoader/Ini/IniReader.cs b/ExtensionLoader/Ini/IniReader.cs index c900d2e3..a25716b6 100644 --- a/ExtensionLoader/Ini/IniReader.cs +++ b/ExtensionLoader/Ini/IniReader.cs @@ -62,7 +62,7 @@ namespace ExtensionLoader.Ini bool disposed = false; bool lineContinuation = false; bool acceptCommentAfterKey = true; - bool acceptNoAssignmentOperator = false; + bool acceptNoAssignmentOperator = true; bool consumeAllKeyText = false; char[] commentDelimiters = new char[] { ';' }; char[] assignDelimiters = new char[] { '=' }; diff --git a/Programs/Simian/Extensions/AccountManager.cs b/Programs/Simian/Extensions/AccountManager.cs index 97ca0bf9..80fba9bf 100644 --- a/Programs/Simian/Extensions/AccountManager.cs +++ b/Programs/Simian/Extensions/AccountManager.cs @@ -72,7 +72,7 @@ namespace Simian.Extensions return accounts.TryGetValue(fullName, out agent); } - #region Persistance + #region Persistence public OSD Serialize() { @@ -109,6 +109,6 @@ namespace Simian.Extensions Helpers.LogLevel.Info); } - #endregion Persistance + #endregion Persistence } } diff --git a/Programs/Simian/Extensions/AvatarManager.cs b/Programs/Simian/Extensions/AvatarManager.cs index 74a9340a..3abcd884 100644 --- a/Programs/Simian/Extensions/AvatarManager.cs +++ b/Programs/Simian/Extensions/AvatarManager.cs @@ -13,6 +13,7 @@ namespace Simian.Extensions Simian server; int currentWearablesSerialNum = -1; int currentAnimSequenceNum = 0; + Timer CoarseLocationTimer; public AvatarManager() { @@ -31,10 +32,19 @@ namespace Simian.Extensions server.UDP.RegisterPacketCallback(PacketType.SoundTrigger, new PacketCallback(SoundTriggerHandler)); server.UDP.RegisterPacketCallback(PacketType.ViewerEffect, new PacketCallback(ViewerEffectHandler)); server.UDP.RegisterPacketCallback(PacketType.UUIDNameRequest, new PacketCallback(UUIDNameRequestHandler)); + + if (CoarseLocationTimer != null) CoarseLocationTimer.Dispose(); + CoarseLocationTimer = new Timer(CoarseLocationTimer_Elapsed); + CoarseLocationTimer.Change(1000, 1000); } public void Stop() { + if (CoarseLocationTimer != null) + { + CoarseLocationTimer.Dispose(); + CoarseLocationTimer = null; + } } public bool SetDefaultAnimation(Agent agent, UUID animID) @@ -367,5 +377,48 @@ namespace Simian.Extensions server.UDP.SendPacket(agent.AgentID, reply, PacketCategory.Transaction); } + + void CoarseLocationTimer_Elapsed(object sender) + { + lock (server.Agents) + { + foreach (Agent recipient in server.Agents.Values) + { + int i = 0; + + CoarseLocationUpdatePacket update = new CoarseLocationUpdatePacket(); + update.Index.Prey = -1; + update.Index.You = 0; + + update.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[server.Agents.Count]; + update.Location = new CoarseLocationUpdatePacket.LocationBlock[server.Agents.Count]; + + // Fill in this avatar + update.AgentData[0] = new CoarseLocationUpdatePacket.AgentDataBlock(); + update.AgentData[0].AgentID = recipient.AgentID; + update.Location[0] = new CoarseLocationUpdatePacket.LocationBlock(); + update.Location[0].X = (byte)((int)recipient.Avatar.Position.X); + update.Location[0].Y = (byte)((int)recipient.Avatar.Position.Y); + update.Location[0].Z = (byte)((int)recipient.Avatar.Position.Z / 4); + ++i; + + foreach (Agent agent in server.Agents.Values) + { + if (agent != recipient) + { + update.AgentData[i] = new CoarseLocationUpdatePacket.AgentDataBlock(); + update.AgentData[i].AgentID = agent.AgentID; + update.Location[i] = new CoarseLocationUpdatePacket.LocationBlock(); + update.Location[i].X = (byte)((int)agent.Avatar.Position.X); + update.Location[i].Y = (byte)((int)agent.Avatar.Position.Y); + update.Location[i].Z = (byte)((int)agent.Avatar.Position.Z / 4); + ++i; + } + } + + server.UDP.SendPacket(recipient.AgentID, update, PacketCategory.State); + } + } + } } } diff --git a/Programs/Simian/Extensions/CoarseLocationUpdates.cs b/Programs/Simian/Extensions/CoarseLocationUpdates.cs deleted file mode 100644 index 90a60748..00000000 --- a/Programs/Simian/Extensions/CoarseLocationUpdates.cs +++ /dev/null @@ -1,77 +0,0 @@ -using OpenMetaverse; -using OpenMetaverse.Packets; -using ExtensionLoader; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace Simian.Extensions -{ - public class CoarseLocationUpdates : IExtension - { - Simian server; - Timer CoarseLocationTimer; - - public CoarseLocationUpdates() - { - } - - public void Start(Simian server) - { - this.server = server; - - if (CoarseLocationTimer != null) CoarseLocationTimer = null; - CoarseLocationTimer = new Timer(new TimerCallback(CoarseLocationTimer_Elapsed)); - CoarseLocationTimer.Change(1000, 1000); - } - - public void Stop() - { - CoarseLocationTimer = null; - } - - void CoarseLocationTimer_Elapsed(object sender) - { - lock (server.Agents) - { - foreach (Agent recipient in server.Agents.Values) - { - int i = 0; - - CoarseLocationUpdatePacket update = new CoarseLocationUpdatePacket(); - update.Index.Prey = -1; - update.Index.You = 0; - - update.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[server.Agents.Count]; - update.Location = new CoarseLocationUpdatePacket.LocationBlock[server.Agents.Count]; - - // Fill in this avatar - update.AgentData[0] = new CoarseLocationUpdatePacket.AgentDataBlock(); - update.AgentData[0].AgentID = recipient.AgentID; - update.Location[0] = new CoarseLocationUpdatePacket.LocationBlock(); - update.Location[0].X = (byte)((int)recipient.Avatar.Position.X); - update.Location[0].Y = (byte)((int)recipient.Avatar.Position.Y); - update.Location[0].Z = (byte)((int)recipient.Avatar.Position.Z / 4); - ++i; - - foreach (Agent agent in server.Agents.Values) - { - if (agent != recipient) - { - update.AgentData[i] = new CoarseLocationUpdatePacket.AgentDataBlock(); - update.AgentData[i].AgentID = agent.AgentID; - update.Location[i] = new CoarseLocationUpdatePacket.LocationBlock(); - update.Location[i].X = (byte)((int)agent.Avatar.Position.X); - update.Location[i].Y = (byte)((int)agent.Avatar.Position.Y); - update.Location[i].Z = (byte)((int)agent.Avatar.Position.Z / 4); - ++i; - } - } - - server.UDP.SendPacket(recipient.AgentID, update, PacketCategory.State); - } - } - } - } -} diff --git a/Programs/Simian/Extensions/Movement.cs b/Programs/Simian/Extensions/Movement.cs index 8aa7a955..038cd3a5 100644 --- a/Programs/Simian/Extensions/Movement.cs +++ b/Programs/Simian/Extensions/Movement.cs @@ -56,7 +56,11 @@ namespace Simian.Extensions public void Stop() { - updateTimer.Dispose(); + if (updateTimer != null) + { + updateTimer.Dispose(); + updateTimer = null; + } } void UpdateTimer_Elapsed(object sender) diff --git a/Programs/Simian/Extensions/RenderingPluginMesher.cs b/Programs/Simian/Extensions/RenderingPluginMesher.cs index 7becb561..0458d8a8 100644 --- a/Programs/Simian/Extensions/RenderingPluginMesher.cs +++ b/Programs/Simian/Extensions/RenderingPluginMesher.cs @@ -19,6 +19,7 @@ namespace Simian.Extensions { this.server = server; + // FIXME: Use the list in Simian.ini // Search for a the best available OpenMetaverse.Rendering plugin List renderers = RenderingLoader.ListRenderers(AppDomain.CurrentDomain.BaseDirectory); diff --git a/Programs/Simian/Extensions/UDPServer.cs b/Programs/Simian/Extensions/UDPManager.cs similarity index 100% rename from Programs/Simian/Extensions/UDPServer.cs rename to Programs/Simian/Extensions/UDPManager.cs diff --git a/Programs/Simian/Simian.cs b/Programs/Simian/Simian.cs index 9dfbc476..c0ce3a3d 100644 --- a/Programs/Simian/Simian.cs +++ b/Programs/Simian/Simian.cs @@ -16,6 +16,8 @@ namespace Simian { public partial class Simian { + public const string CONFIG_FILE = "Simian.ini"; + // TODO: Don't hard-code these public const uint REGION_X = 256000; public const uint REGION_Y = 256000; @@ -25,6 +27,7 @@ namespace Simian public string DataDir = "SimianData/"; public HttpServer HttpServer; + public IniConfigSource ConfigFile; public ulong RegionHandle; // Interfaces @@ -52,6 +55,20 @@ namespace Simian { HttpPort = port; UDPPort = port; + List extensionList = null; + + try + { + // Load the extension list (and ordering) from our config file + ConfigFile = new IniConfigSource(CONFIG_FILE); + IConfig extensionConfig = ConfigFile.Configs["Extensions"]; + extensionList = new List(extensionConfig.GetKeys()); + } + catch (Exception) + { + Logger.Log("Failed to load [Extensions] section from " + CONFIG_FILE, Helpers.LogLevel.Error); + return false; + } InitHttpServer(HttpPort, ssl); @@ -68,7 +85,7 @@ namespace Simian List assignables = ExtensionLoader.GetInterfaces(this); ExtensionLoader.LoadAllExtensions(Assembly.GetExecutingAssembly(), - AppDomain.CurrentDomain.BaseDirectory, this, references, + AppDomain.CurrentDomain.BaseDirectory, this, extensionList, references, "Simian.*.dll", "Simian.*.cs", this, assignables); } catch (ExtensionException ex) @@ -85,24 +102,19 @@ namespace Simian PersistentExtensions.Add((IPersistable)extension); } - foreach (IExtension extension in ExtensionLoader.Extensions) + for (int i = 0; i < extensionList.Count; i++) { // Start all extensions except for persistence providers - if (!(extension is IPersistenceProvider)) - { - Logger.DebugLog("Loading extension " + extension.GetType().Name); - extension.Start(this); - } - } - - foreach (IExtension extension in ExtensionLoader.Extensions) - { - // Start the persistence provider(s) after all other extensions are loaded - if (extension is IPersistenceProvider) - { - Logger.DebugLog("Loading persistance provider " + extension.GetType().Name); - extension.Start(this); - } + ExtensionLoader.Extensions.ForEach( + delegate(IExtension extension) + { + if (extension.GetType().Name == extensionList[i]) + { + Logger.DebugLog("Starting extension " + extensionList[i]); + extension.Start(this); + } + } + ); } return true; @@ -149,19 +161,19 @@ namespace Simian void InitHttpServer(int port, bool ssl) { - HttpServer = new HttpServer(HttpPort, ssl); + HttpServer = new HttpServer(port, ssl); // Login webpage HEAD request, used to check if the login webpage is alive - HttpServer.AddHandler("head", null, "^/loginpage", new HttpServer.HttpRequestCallback(LoginWebpageHeadHandler)); + HttpServer.AddHandler("head", null, "^/loginpage", LoginWebpageHeadHandler); // Login webpage GET request, gets the login webpage data (purely aesthetic) - HttpServer.AddHandler("get", null, "^/loginpage", new HttpServer.HttpRequestCallback(LoginWebpageGetHandler)); + HttpServer.AddHandler("get", null, "^/loginpage", LoginWebpageGetHandler); // Client XML-RPC login - HttpServer.AddHandler("post", "text/xml", "^/login", new HttpServer.HttpRequestCallback(LoginXmlRpcPostHandler)); + HttpServer.AddHandler("post", "text/xml", "^/login", LoginXmlRpcPostHandler); // Client LLSD login - HttpServer.AddHandler("post", "application/xml", "^/login", new HttpServer.HttpRequestCallback(LoginLLSDPostHandler)); + HttpServer.AddHandler("post", "application/xml", "^/login", LoginLLSDPostHandler); HttpServer.Start(); } @@ -170,6 +182,7 @@ namespace Simian { context.Response.StatusCode = (int)HttpStatusCode.OK; context.Response.StatusDescription = "OK"; + context.Response.Close(); } void LoginWebpageGetHandler(HttpRequestSignature signature, ref HttpListenerContext context) diff --git a/bin/Simian.ini b/bin/Simian.ini new file mode 100644 index 00000000..ec879e7f --- /dev/null +++ b/bin/Simian.ini @@ -0,0 +1,87 @@ +[Extensions] + +; Handles sending and receiving packets in the LLUDP format +UDPManager + +; LLUDP connection management. Allows agents to connect and disconnect from a +; simulator, as well as keeping the UDP connection alive. +ConnectionManager + +; Creates an account for anyone who logs in. The account will be registered +; with the account provider so persistence between sessions is possible, but +; no form of authentication or authorization is done +AuthFreeForAll + +; +; ---Local Simulator Stores--- +; +; The following extensions use persistence, but do not communicate with a +; remote server or other simulators. These extensions are only useful for a +; single simulator running in standalone mode, and will have unexpected results +; if the simulator is part of a larger grid. + +; A simulator-local account store +AccountManager + +; A simulator-local asset store using the filesystem to store assets +AssetManager + +; A simulator-local inventory store +InventoryManager + +; +; ---End Local Simulator Stores--- +; + +; Various avatar-related functions including appearance, animations and sounds +AvatarManager + +; Friendship management and alerts +FriendManager + +; Texture downloads +ImageDelivery + +; Chat and instant messaging +Messaging + +; Money management and accounting functions +Money + +; A simple physics engine for avatar movement. Supports walking, flying, and +; swimming as well as avatar-avatar collisions. Does not support avatar-prim +; or prim-prim collisions. +Movement + +; Object creation, editing, deleting, etc. Processes packets and passes events +; to the scene provider. +ObjectManager + +; Parcel management +ParcelManager + +; Converts prims into 3D geometry data. This is only used if a physics engine +; is present that makes use of prim mesh data. +RenderingPluginMesher + +; Main scene graph engine. All spatial events are processed through here. +SceneManager + +; +; ---Persistence Providers--- +; +; The following extensions allow extensions that use persistence to save +; state between simulator runs. Only one persistence provider should be +; active. + +; Persistence provider using LLSD XML serialization +XMLPersistence + +[Meshers] + +; Meshing plugins are listed in order of preference. If the first plugin is not +; found the next is loaded, and so on. The items listed are used as search +; strings, so the exact dll name is not needed +OpenMetaverse.Rendering.GPL +OpenMetaverse.Rendering.Meshmerizer +OpenMetaverse.Rendering.Simple