* Fixed a nasty OSD->JSON bug that was producing invalid JSON for empty arrays or dictionaries

* Several fixes in OpenMetaverse.Http.CapsServer and OpenMetaverse.Http.EventQueueServer (this is the first time they've been tested)
[Simian]
* Initial capabilities and EventQueue support (appears to be working)
* HyperGrid is almost working
* More cleanup with how agents are removed from the scene

git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@2427 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2009-02-04 23:00:33 +00:00
parent 875aa0b6e8
commit 808b681b83
17 changed files with 689 additions and 138 deletions

View File

@@ -23,12 +23,12 @@ namespace Simian.Extensions
{
this.server = server;
UploadDir = Path.Combine(server.DataDir, UPLOAD_DIR);
UploadDir = Path.Combine(Simian.DATA_DIR, UPLOAD_DIR);
// Try to create the data directories if they don't already exist
if (!Directory.Exists(server.DataDir))
if (!Directory.Exists(Simian.DATA_DIR))
{
try { Directory.CreateDirectory(server.DataDir); }
try { Directory.CreateDirectory(Simian.DATA_DIR); }
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Warning, ex); }
}
if (!Directory.Exists(UploadDir))
@@ -37,7 +37,7 @@ namespace Simian.Extensions
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Warning, ex); }
}
LoadAssets(server.DataDir);
LoadAssets(Simian.DATA_DIR);
LoadAssets(UploadDir);
}

View File

@@ -106,26 +106,6 @@ namespace Simian.Extensions
server.UDP.BroadcastPacket(sound, PacketCategory.State);
}
public void Disconnect(Agent agent)
{
// Remove the avatar from the scene
SimulationObject obj;
if (server.Scene.TryGetObject(agent.Avatar.ID, out obj))
server.Scene.ObjectRemove(this, obj.Prim.LocalID);
else
Logger.Log("Disconnecting an agent that is not in the scene", Helpers.LogLevel.Warning);
// Remove the UDP client
server.UDP.RemoveClient(agent);
// HACK: Notify everyone when someone disconnects
OfflineNotificationPacket offline = new OfflineNotificationPacket();
offline.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[1];
offline.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock();
offline.AgentBlock[0].AgentID = agent.Avatar.ID;
server.UDP.BroadcastPacket(offline, PacketCategory.State);
}
public void SendAlert(Agent agent, string message)
{
AlertMessagePacket alert = new AlertMessagePacket();
@@ -450,8 +430,16 @@ namespace Simian.Extensions
update.Index.Prey = -1;
update.Index.You = 0;
update.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[agentDatas.Count - 1];
update.Location = new CoarseLocationUpdatePacket.LocationBlock[agentDatas.Count - 1];
// Count the number of blocks to send out
int count = 0;
for (int i = 0; i < agentDatas.Count; i++)
{
if (agentDatas[i].AgentID != agent.Avatar.ID)
++count;
}
update.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[count];
update.Location = new CoarseLocationUpdatePacket.LocationBlock[count];
int j = 0;
for (int i = 0; i < agentDatas.Count; i++)

View File

@@ -13,7 +13,6 @@ namespace Simian.Extensions
{
Simian server;
CapsServer capsServer;
Dictionary<UUID, EventQueueServer> eventQueues = new Dictionary<UUID, EventQueueServer>();
public CapsManager()
{
@@ -22,47 +21,45 @@ namespace Simian.Extensions
public void Start(Simian server)
{
this.server = server;
capsServer = new CapsServer(server.HttpServer, @"^/caps/");
capsServer = new CapsServer(server.HttpServer, @"^/caps/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
capsServer.Start();
}
public void Stop()
{
lock (eventQueues)
{
foreach (EventQueueServer eventQueue in eventQueues.Values)
eventQueue.Stop();
}
capsServer.Stop();
}
public UUID CreateCapability(HttpServer.HttpRequestCallback localHandler, bool clientCertRequired)
public Uri CreateCapability(CapsRequestCallback localHandler, bool clientCertRequired, object state)
{
return capsServer.CreateCapability(localHandler, clientCertRequired);
UUID capID = capsServer.CreateCapability(localHandler, clientCertRequired, state);
return new Uri(
(server.SSL ? "https://" : "http://") +
server.HostName +
(server.HttpPort == 80 ? String.Empty : ":" + server.HttpPort) +
"/caps/" + capID.ToString());
}
public UUID CreateCapability(Uri remoteHandler, bool clientCertRequired)
public Uri CreateCapability(Uri remoteHandler, bool clientCertRequired)
{
return capsServer.CreateCapability(remoteHandler, clientCertRequired);
UUID capID = capsServer.CreateCapability(remoteHandler, clientCertRequired);
return new Uri(
(server.SSL ? "https://" : "http://") +
server.HostName +
(server.HttpPort == 80 ? String.Empty : ":" + server.HttpPort) +
"/caps/" + capID.ToString());
}
public bool RemoveCapability(UUID capID)
public bool RemoveCapability(Uri cap)
{
return capsServer.RemoveCapability(capID);
}
string path = cap.PathAndQuery.TrimEnd('/');
UUID capID;
public void SendEvent(Agent agent, string name, OSDMap body)
{
EventQueueServer eventQueue;
if (eventQueues.TryGetValue(agent.Avatar.ID, out eventQueue))
{
eventQueue.SendEvent(name, body);
}
// Parse the capability UUID out of the URI
if (UUID.TryParse(path.Substring(path.Length - 36), out capID))
return capsServer.RemoveCapability(capID);
else
{
Logger.Log(String.Format("Cannot send the event {0} to agent {1} {2}, no event queue for that avatar",
name, agent.FirstName, agent.LastName), Helpers.LogLevel.Warning);
}
return false;
}
}
}

View File

@@ -82,7 +82,7 @@ namespace Simian.Extensions
server.UDP.SendPacket(agent.Avatar.ID, reply, PacketCategory.Transaction);
server.Avatars.Disconnect(agent);
server.Scene.ObjectRemove(this, agent.Avatar.ID);
}
}
}

View File

@@ -141,10 +141,16 @@ namespace Simian.Extensions
if (responseData.Success)
responseData.InventorySkeleton = server.Inventory.CreateInventorySkeleton(responseData.AgentID);
XmlWriter writer = XmlWriter.Create(response.Body);
responseData.ToXmlRpc(writer);
writer.Flush();
writer.Close();
MemoryStream memoryStream = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(memoryStream))
{
responseData.ToXmlRpc(writer);
writer.Flush();
}
response.ContentLength = memoryStream.Length;
response.Body.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
response.Body.Flush();
}
catch (Exception ex)
{
@@ -178,6 +184,9 @@ namespace Simian.Extensions
// Authentication successful, create a login instance of this agent
agent = server.Accounts.CreateInstance(agentID);
// Create a seed capability for this agent
Uri seedCap = server.Capabilities.CreateCapability(server.Scene.SeedCapabilityHandler, false, agentID);
if (agent != null)
{
// Assign a circuit code and insert the agent into the unassociatedAgents dictionary
@@ -217,8 +226,7 @@ namespace Simian.Extensions
response.RegionY = regionY;
response.SecondsSinceEpoch = DateTime.Now;
// FIXME: Actually generate a seed capability
response.SeedCapability = String.Format("http://{0}:{1}/seed_caps", simIP, server.HttpPort);
response.SeedCapability = seedCap.ToString();
response.SimIP = simIP;
response.SimPort = (ushort)server.UDPPort;
response.StartLocation = "last"; // FIXME:

View File

@@ -1,10 +1,24 @@
using System;
using System.IO;
using System.Net;
using System.Xml;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.StructuredData;
namespace Simian.Extensions
{
class HyperGridLink
{
public string RegionName;
public ulong RegionHandle;
public UUID RegionID;
public UUID RegionImage;
public int UDPPort;
public int RemotingPort;
}
public class MapLocal : IExtension<Simian>
{
Simian server;
@@ -84,6 +98,8 @@ namespace Simian.Extensions
{
TeleportRequestPacket request = (TeleportRequestPacket)packet;
// TODO: Stand the avatar up first
if (request.Info.RegionID == server.Scene.RegionID)
{
// Local teleport
@@ -102,7 +118,11 @@ namespace Simian.Extensions
}
else
{
Logger.Log("Ignoring teleport request to " + request.Info.RegionID, Helpers.LogLevel.Warning);
TeleportFailedPacket reply = new TeleportFailedPacket();
reply.Info.AgentID = agent.Avatar.ID;
reply.Info.Reason = Utils.StringToBytes("Unknown region");
server.UDP.SendPacket(agent.Avatar.ID, reply, PacketCategory.Transaction);
}
}
@@ -110,6 +130,8 @@ namespace Simian.Extensions
{
TeleportLocationRequestPacket request = (TeleportLocationRequestPacket)packet;
// TODO: Stand the avatar up first
if (request.Info.RegionHandle == server.Scene.RegionHandle)
{
// Local teleport
@@ -126,10 +148,410 @@ namespace Simian.Extensions
server.UDP.SendPacket(agent.Avatar.ID, reply, PacketCategory.Transaction);
}
else if (request.Info.RegionHandle == Utils.UIntsToLong((server.Scene.RegionX + 1) * 256, server.Scene.RegionY * 256))
{
// Special case: adjacent simulator is the HyperGrid portal
HyperGridTeleport(agent, new Uri(/*"http://192.168.1.2:9010/"*/ "http://osl2.nac.uci.edu:9006/"), request.Info.Position);
}
else
{
Logger.Log("Ignoring teleport request to " + request.Info.RegionHandle, Helpers.LogLevel.Warning);
TeleportFailedPacket reply = new TeleportFailedPacket();
reply.Info.AgentID = agent.Avatar.ID;
reply.Info.Reason = Utils.StringToBytes("Unknown region");
server.UDP.SendPacket(agent.Avatar.ID, reply, PacketCategory.Transaction);
}
}
bool HyperGridTeleport(Agent agent, Uri destination, Vector3 destPos)
{
HyperGridLink link;
TeleportProgress(agent, "Resolving destination IP address", TeleportFlags.ViaLocation);
IPHostEntry entry = Dns.GetHostEntry(destination.DnsSafeHost);
if (entry.AddressList != null && entry.AddressList.Length >= 1)
{
TeleportProgress(agent, "Retrieving destination details", TeleportFlags.ViaLocation);
if (LinkRegion(destination, out link))
{
TeleportProgress(agent, "Creating foreign agent", TeleportFlags.ViaLocation);
if (ExpectHyperGridUser(agent, destination, destPos, link))
{
TeleportProgress(agent, "Establishing foreign agent presence", TeleportFlags.ViaLocation);
// This is a crufty part of the HyperGrid protocol. We need to generate a fragment of a UUID
// (missing the last four digits) and send that as the caps_path variable. Locally, we expand
// that out to http://foreignsim:httpport/CAPS/fragment0000/ and use it as the seed caps path
// that is sent to the client
UUID seedID = UUID.Random();
string seedCapFragment = seedID.ToString().Substring(0, 32);
Uri seedCap = new Uri(destination, "/CAPS/" + seedCapFragment + "0000/");
if (CreateChildAgent(agent, destination, destPos, link, seedCapFragment))
{
// Send the final teleport packet to the client
TeleportFinishPacket teleport = new TeleportFinishPacket();
teleport.Info.AgentID = agent.Avatar.ID;
teleport.Info.LocationID = 0; // Unused by the client
teleport.Info.RegionHandle = link.RegionHandle;
teleport.Info.SeedCapability = Utils.StringToBytes(seedCap.ToString());
teleport.Info.SimAccess = (byte)SimAccess.Min;
teleport.Info.SimIP = Utils.BytesToUInt(entry.AddressList[0].GetAddressBytes());
teleport.Info.SimPort = (ushort)link.UDPPort;
teleport.Info.TeleportFlags = (uint)TeleportFlags.ViaLocation;
server.UDP.SendPacket(agent.Avatar.ID, teleport, PacketCategory.Transaction);
// Remove the agent from the local scene (will also tear down the UDP connection)
//server.Scene.ObjectRemove(this, agent.Avatar.ID);
return true;
}
}
}
}
return false;
}
bool LinkRegion(Uri destination, out HyperGridLink link)
{
try
{
#region Build Request
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(destination);
request.Method = "POST";
request.ContentType = "text/xml";
MemoryStream memoryStream = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(memoryStream))
{
writer.WriteStartElement("methodCall");
{
writer.WriteElementString("methodName", "link_region");
writer.WriteStartElement("params");
writer.WriteStartElement("param");
writer.WriteStartElement("value");
writer.WriteStartElement("struct");
{
WriteStringMember(writer, "region_name", String.Empty);
}
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.Flush();
}
request.ContentLength = memoryStream.Length;
using (Stream writeStream = request.GetRequestStream())
{
writeStream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
}
#endregion Build Request
#region Parse Response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreWhitespace = true;
using (XmlReader reader = XmlReader.Create(response.GetResponseStream(), settings))
{
link = new HyperGridLink();
reader.ReadStartElement("methodResponse");
{
reader.ReadStartElement("params");
reader.ReadStartElement("param");
reader.ReadStartElement("value");
reader.ReadStartElement("struct");
{
while (reader.Name == "member")
{
reader.ReadStartElement("member");
{
string name = reader.ReadElementContentAsString("name", String.Empty);
reader.ReadStartElement("value");
{
switch (name)
{
case "region_name":
link.RegionName = reader.ReadElementContentAsString("string", String.Empty);
break;
case "handle":
string handle = reader.ReadElementContentAsString("string", String.Empty);
link.RegionHandle = UInt64.Parse(handle);
break;
case "uuid":
string uuid = reader.ReadElementContentAsString("string", String.Empty);
link.RegionID = UUID.Parse(uuid);
break;
case "internal_port":
link.UDPPort = reader.ReadElementContentAsInt("string", String.Empty);
break;
case "region_image":
string imageuuid = reader.ReadElementContentAsString("string", String.Empty);
link.RegionImage = UUID.Parse(imageuuid);
break;
case "remoting_port":
link.RemotingPort = reader.ReadElementContentAsInt("string", String.Empty);
break;
default:
Logger.Log("[HyperGrid] Unrecognized response XML chunk: " + reader.ReadInnerXml(),
Helpers.LogLevel.Warning);
break;
}
}
reader.ReadEndElement();
}
reader.ReadEndElement();
}
}
reader.ReadEndElement();
reader.ReadEndElement();
reader.ReadEndElement();
reader.ReadEndElement();
}
reader.ReadEndElement();
return true;
}
#endregion Parse Response
}
catch (Exception ex)
{
Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
}
link = null;
return false;
}
bool ExpectHyperGridUser(Agent agent, Uri destination, Vector3 destPos, HyperGridLink link)
{
try
{
#region Build Request
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(destination);
request.Method = "POST";
request.ContentType = "text/xml";
MemoryStream memoryStream = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(memoryStream))
{
writer.WriteStartElement("methodCall");
{
writer.WriteElementString("methodName", "expect_hg_user");
writer.WriteStartElement("params");
writer.WriteStartElement("param");
writer.WriteStartElement("value");
writer.WriteStartElement("struct");
{
WriteStringMember(writer, "session_id", agent.SessionID.ToString());
WriteStringMember(writer, "secure_session_id", agent.SecureSessionID.ToString());
WriteStringMember(writer, "firstname", agent.FirstName);
WriteStringMember(writer, "lastname", agent.LastName);
WriteStringMember(writer, "agent_id", agent.Avatar.ID.ToString());
WriteStringMember(writer, "circuit_code", agent.CircuitCode.ToString());
WriteStringMember(writer, "startpos_x", destPos.X.ToString(Utils.EnUsCulture));
WriteStringMember(writer, "startpos_y", destPos.Y.ToString(Utils.EnUsCulture));
WriteStringMember(writer, "startpos_z", destPos.Z.ToString(Utils.EnUsCulture));
WriteStringMember(writer, "caps_path", String.Empty);
WriteStringMember(writer, "region_uuid", link.RegionID.ToString());
//WriteStringMember(writer, "userserver_id", "");
//WriteStringMember(writer, "assetserver_id", "");
//WriteStringMember(writer, "inventoryserver_id", "");
WriteStringMember(writer, "root_folder_id", agent.InventoryRoot.ToString());
WriteStringMember(writer, "internal_port", server.HttpPort.ToString());
WriteStringMember(writer, "regionhandle", link.RegionHandle.ToString());
WriteStringMember(writer, "home_address", IPAddress.Loopback.ToString());
WriteStringMember(writer, "home_port", server.HttpPort.ToString());
WriteStringMember(writer, "home_remoting", server.HttpPort.ToString());
}
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.Flush();
}
request.ContentLength = memoryStream.Length;
using (Stream writeStream = request.GetRequestStream())
{
writeStream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
}
#endregion Build Request
#region Parse Response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreWhitespace = true;
using (XmlReader reader = XmlReader.Create(response.GetResponseStream(), settings))
{
bool success = false;
string reason = String.Empty;
reader.ReadStartElement("methodResponse");
{
reader.ReadStartElement("params");
reader.ReadStartElement("param");
reader.ReadStartElement("value");
reader.ReadStartElement("struct");
{
while (reader.Name == "member")
{
reader.ReadStartElement("member");
{
string name = reader.ReadElementContentAsString("name", String.Empty);
reader.ReadStartElement("value");
{
switch (name)
{
case "success":
success = (reader.ReadElementContentAsString("string", String.Empty).ToUpper() == "TRUE");
break;
case "reason":
reason = reader.ReadElementContentAsString("string", String.Empty);
break;
default:
Logger.Log("[HyperGrid] Unrecognized response XML chunk: " + reader.ReadInnerXml(),
Helpers.LogLevel.Warning);
break;
}
}
reader.ReadEndElement();
}
reader.ReadEndElement();
}
}
reader.ReadEndElement();
reader.ReadEndElement();
reader.ReadEndElement();
reader.ReadEndElement();
}
reader.ReadEndElement();
if (!success)
Logger.Log("[HyperGrid] Teleport failed, reason: " + reason, Helpers.LogLevel.Warning);
return success;
}
#endregion Parse Response
}
catch (Exception ex)
{
Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
}
return false;
}
bool CreateChildAgent(Agent agent, Uri destination, Vector3 destPos, HyperGridLink link, string seedCapFragment)
{
try
{
destination = new Uri(destination, "/agent/" + agent.Avatar.ID.ToString() + "/");
OSDMap args = new OSDMap();
args["agent_id"] = OSD.FromUUID(agent.Avatar.ID);
args["base_folder"] = OSD.FromUUID(UUID.Zero);
args["caps_path"] = OSD.FromString(seedCapFragment);
args["children_seeds"] = OSD.FromBoolean(false);
args["child"] = OSD.FromBoolean(false);
args["circuit_code"] = OSD.FromString(agent.CircuitCode.ToString());
args["first_name"] = OSD.FromString(agent.FirstName);
args["last_name"] = OSD.FromString(agent.LastName);
args["inventory_folder"] = OSD.FromUUID(agent.InventoryRoot);
args["secure_session_id"] = OSD.FromUUID(agent.SecureSessionID);
args["session_id"] = OSD.FromUUID(agent.SessionID);
args["start_pos"] = OSD.FromString(destPos.ToString());
args["destination_handle"] = OSD.FromString(link.RegionHandle.ToString());
LitJson.JsonData jsonData = OSDParser.SerializeJson(args);
byte[] data = System.Text.Encoding.UTF8.GetBytes(jsonData.ToJson());
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(destination);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(data, 0, data.Length);
requestStream.Flush();
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
bool success = false;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
Boolean.TryParse(reader.ReadToEnd(), out success);
}
return success;
}
catch (Exception ex)
{
Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
}
return false;
}
void TeleportProgress(Agent agent, string message, TeleportFlags flags)
{
TeleportProgressPacket progress = new TeleportProgressPacket();
progress.AgentData.AgentID = agent.Avatar.ID;
progress.Info.Message = Utils.StringToBytes(message);
progress.Info.TeleportFlags = (uint)flags;
server.UDP.SendPacket(agent.Avatar.ID, progress, PacketCategory.Transaction);
}
static void WriteStringMember(XmlWriter writer, string name, string value)
{
writer.WriteStartElement("member");
{
writer.WriteElementString("name", name);
writer.WriteStartElement("value");
{
writer.WriteElementString("string", value);
}
writer.WriteEndElement();
}
writer.WriteEndElement();
}
}
}

View File

@@ -3,22 +3,37 @@ using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Threading;
using ExtensionLoader;
using HttpServer;
using OpenMetaverse;
using OpenMetaverse.Imaging;
using OpenMetaverse.Packets;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Http;
namespace Simian.Extensions
{
class EventQueueServerCap
{
public EventQueueServer Server;
public Uri Capability;
public EventQueueServerCap(EventQueueServer server, Uri capability)
{
Server = server;
Capability = capability;
}
}
public class SceneManager : IExtension<Simian>, ISceneProvider
{
Simian server;
DoubleDictionary<uint, UUID, SimulationObject> sceneObjects = new DoubleDictionary<uint, UUID, SimulationObject>();
DoubleDictionary<uint, UUID, Agent> sceneAgents = new DoubleDictionary<uint, UUID, Agent>();
Dictionary<UUID, EventQueueServerCap> eventQueues = new Dictionary<UUID, EventQueueServerCap>();
int currentLocalID = 1;
ulong regionHandle;
UUID regionID = UUID.Random();
@@ -57,11 +72,19 @@ namespace Simian.Extensions
this.server = server;
server.UDP.RegisterPacketCallback(PacketType.CompleteAgentMovement, new PacketCallback(CompleteAgentMovementHandler));
LoadTerrain(server.DataDir + "heightmap.tga");
LoadTerrain(Simian.DATA_DIR + "heightmap.tga");
}
public void Stop()
{
lock (eventQueues)
{
foreach (EventQueueServerCap eventQueue in eventQueues.Values)
{
server.Capabilities.RemoveCapability(eventQueue.Capability);
eventQueue.Server.Stop();
}
}
}
public float[,] GetTerrainPatch(uint x, uint y)
@@ -150,14 +173,7 @@ namespace Simian.Extensions
if (OnAgentRemove != null)
OnAgentRemove(sender, agent);
sceneAgents.Remove(agent.Avatar.LocalID, agent.Avatar.ID);
KillObjectPacket kill = new KillObjectPacket();
kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
kill.ObjectData[0].ID = agent.Avatar.LocalID;
server.UDP.BroadcastPacket(kill, PacketCategory.State);
AgentRemove(agent);
return true;
}
else
@@ -193,14 +209,7 @@ namespace Simian.Extensions
if (OnAgentRemove != null)
OnAgentRemove(sender, agent);
sceneAgents.Remove(agent.Avatar.LocalID, agent.Avatar.ID);
KillObjectPacket kill = new KillObjectPacket();
kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
kill.ObjectData[0].ID = agent.Avatar.LocalID;
server.UDP.BroadcastPacket(kill, PacketCategory.State);
AgentRemove(agent);
return true;
}
else
@@ -210,6 +219,33 @@ namespace Simian.Extensions
}
}
void AgentRemove(Agent agent)
{
Logger.Log("Removing agent " + agent.FullName + " from the scene", Helpers.LogLevel.Info);
sceneAgents.Remove(agent.Avatar.LocalID, agent.Avatar.ID);
KillObjectPacket kill = new KillObjectPacket();
kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
kill.ObjectData[0].ID = agent.Avatar.LocalID;
server.UDP.BroadcastPacket(kill, PacketCategory.State);
// Kill the EventQueue
RemoveEventQueue(agent.Avatar.ID);
// Remove the UDP client
server.UDP.RemoveClient(agent);
// Notify everyone in the scene that this agent has gone offline
OfflineNotificationPacket offline = new OfflineNotificationPacket();
offline.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[1];
offline.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock();
offline.AgentBlock[0].AgentID = agent.Avatar.ID;
server.UDP.BroadcastPacket(offline, PacketCategory.State);
}
public void ObjectTransform(object sender, uint localID, Vector3 position, Quaternion rotation,
Vector3 velocity, Vector3 acceleration, Vector3 angularVelocity)
{
@@ -420,6 +456,87 @@ namespace Simian.Extensions
sceneAgents.ForEach(action);
}
public bool SeedCapabilityHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
{
UUID agentID = (UUID)state;
OSDArray array = OSDParser.DeserializeLLSDXml(request.Body) as OSDArray;
if (array != null)
{
OSDMap osdResponse = new OSDMap();
for (int i = 0; i < array.Count; i++)
{
string capName = array[i].AsString();
switch (capName)
{
case "EventQueueGet":
Uri eqCap = null;
// Check if this agent already has an event queue
EventQueueServerCap eqServer;
if (eventQueues.TryGetValue(agentID, out eqServer))
eqCap = eqServer.Capability;
// If not, create one
if (eqCap == null)
eqCap = CreateEventQueue(agentID);
osdResponse.Add("EventQueueGet", OSD.FromUri(eqCap));
break;
}
}
byte[] responseData = OSDParser.SerializeLLSDXmlBytes(osdResponse);
response.ContentLength = responseData.Length;
response.Body.Write(responseData, 0, responseData.Length);
response.Body.Flush();
}
else
{
response.Status = HttpStatusCode.BadRequest;
}
return true;
}
public Uri CreateEventQueue(UUID agentID)
{
EventQueueServer eqServer = new EventQueueServer(server.HttpServer);
EventQueueServerCap eqServerCap = new EventQueueServerCap(eqServer,
server.Capabilities.CreateCapability(EventQueueHandler, false, eqServer));
eventQueues.Add(agentID, eqServerCap);
return eqServerCap.Capability;
}
public bool RemoveEventQueue(UUID agentID)
{
return eventQueues.Remove(agentID);
}
public void SendEvent(Agent agent, string name, OSDMap body)
{
EventQueueServerCap eventQueue;
if (eventQueues.TryGetValue(agent.Avatar.ID, out eventQueue))
{
eventQueue.Server.SendEvent(name, body);
}
else
{
Logger.Log(String.Format("Cannot send the event {0} to agent {1}, no event queue for that avatar",
name, agent.FullName), Helpers.LogLevel.Warning);
}
}
bool EventQueueHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
{
EventQueueServer eqServer = (EventQueueServer)state;
return eqServer.EventQueueHandler(context, request, response);
}
void BroadcastObjectUpdate(Primitive prim)
{
ObjectUpdatePacket update =

View File

@@ -186,7 +186,7 @@ namespace Simian
lock (unassociatedAgents)
unassociatedAgents[circuitCode] = agent;
Logger.Log("Created a circuit for " + agent.FirstName, Helpers.LogLevel.Info);
Logger.Log("Created circuit " + circuitCode + " for " + agent.FirstName, Helpers.LogLevel.Info);
return circuitCode;
}
@@ -411,7 +411,7 @@ namespace Simian
Logger.Log(String.Format("Ack timeout for {0}, disconnecting", client.Agent.Avatar.Name),
Helpers.LogLevel.Warning);
server.Avatars.Disconnect(client.Agent);
server.Scene.ObjectRemove(this, client.Agent.Avatar.ID);
return;
}
}

View File

@@ -24,7 +24,7 @@ namespace Simian.Extensions
try
{
XmlTextReader reader = new XmlTextReader(File.OpenRead(server.DataDir + "simiandata.xml"));
XmlTextReader reader = new XmlTextReader(File.OpenRead(Simian.DATA_DIR + "simiandata.xml"));
osd = OSDParser.DeserializeLLSDXml(reader);
reader.Close();
}
@@ -76,7 +76,7 @@ namespace Simian.Extensions
try
{
XmlTextWriter writer = new XmlTextWriter(server.DataDir + "simiandata.xml", System.Text.Encoding.UTF8);
XmlTextWriter writer = new XmlTextWriter(Simian.DATA_DIR + "simiandata.xml", System.Text.Encoding.UTF8);
writer.Formatting = Formatting.Indented;
writer.WriteStartElement("llsd");
OSDParser.SerializeLLSDXmlElement(writer, dictionary);