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