[Simian]
* Sim to sim caps for establishing child agents * Still working out a bug in the libomv event queue, committing what is done for now git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@2485 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
@@ -6,6 +6,7 @@ using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using ExtensionLoader;
|
||||
using HttpServer;
|
||||
@@ -92,9 +93,7 @@ namespace Simian
|
||||
public IPEndPoint IPAndPort { get { return endpoint; } set { endpoint = value; } }
|
||||
public Vector3 DefaultPosition { get { return defaultPosition; } }
|
||||
public Vector3 DefaultLookAt { get { return defaultLookAt; } }
|
||||
|
||||
public float WaterHeight { get { return 20f; } }
|
||||
|
||||
public uint TerrainPatchWidth { get { return 16; } }
|
||||
public uint TerrainPatchHeight { get { return 16; } }
|
||||
public uint TerrainPatchCountWidth { get { return 16; } }
|
||||
@@ -119,22 +118,27 @@ namespace Simian
|
||||
string regionName;
|
||||
Vector3 defaultPosition = new Vector3(128f, 128f, 30f);
|
||||
Vector3 defaultLookAt = Vector3.UnitX;
|
||||
/// <summary>Track the eight neighboring tiles around us</summary>
|
||||
RegionInfo[] neighbors = new RegionInfo[8];
|
||||
/// <summary>List of callback URIs for pending client connections. When a new client connection
|
||||
/// is established for a client in this dictionary, an enable_client_complete message will be
|
||||
/// sent to the associated URI</summary>
|
||||
Dictionary<UUID, Uri> enableClientCompleteCallbacks = new Dictionary<UUID, Uri>();
|
||||
|
||||
public SceneManager()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Start(Simian server, string name, IPEndPoint endpoint, UUID regionID, uint regionX, uint regionY,
|
||||
string defaultTerrainFile, int staticObjects, int physicalObjects)
|
||||
public bool Start(Simian server, RegionInfo regionInfo, X509Certificate2 regionCert, string defaultTerrainFile, int staticObjects, int physicalObjects)
|
||||
{
|
||||
this.server = server;
|
||||
this.regionName = name;
|
||||
this.endpoint = endpoint;
|
||||
this.regionID = regionID;
|
||||
this.regionName = regionInfo.Name;
|
||||
this.endpoint = regionInfo.IPAndPort;
|
||||
this.regionID = regionInfo.ID;
|
||||
|
||||
// Set the properties because this will automatically update the regionHandle
|
||||
RegionX = regionX;
|
||||
RegionY = regionY;
|
||||
RegionX = regionInfo.X;
|
||||
RegionY = regionInfo.Y;
|
||||
|
||||
#region ISceneProvider Extension Loading
|
||||
|
||||
@@ -159,7 +163,10 @@ namespace Simian
|
||||
// Start all of the extensions
|
||||
foreach (IExtension<ISceneProvider> extension in extensions.Extensions)
|
||||
{
|
||||
Logger.Log("Starting Scene extension " + extension.GetType().Name, Helpers.LogLevel.Info);
|
||||
// Only print the extension names if this is the first loaded scene
|
||||
if (server.Scenes.Count == 0)
|
||||
Logger.Log("Starting Scene extension " + extension.GetType().Name, Helpers.LogLevel.Info);
|
||||
|
||||
extension.Start(this);
|
||||
}
|
||||
}
|
||||
@@ -172,16 +179,33 @@ namespace Simian
|
||||
|
||||
#endregion ISceneProvider Extension Loading
|
||||
|
||||
udp.RegisterPacketCallback(PacketType.CompleteAgentMovement, new PacketCallback(CompleteAgentMovementHandler));
|
||||
// Callback registration
|
||||
server.Grid.OnRegionUpdate += Grid_OnRegionUpdate;
|
||||
udp.OnAgentConnection += udp_OnAgentConnection;
|
||||
udp.RegisterPacketCallback(PacketType.CompleteAgentMovement, CompleteAgentMovementHandler);
|
||||
udp.RegisterPacketCallback(PacketType.ChatFromViewer, ChatHandler);
|
||||
|
||||
if (!String.IsNullOrEmpty(defaultTerrainFile))
|
||||
LoadTerrain(Simian.DATA_DIR + defaultTerrainFile);
|
||||
|
||||
Logger.Log(String.Format("Region {0} online at ({1},{2}) listening on {3}", name, regionX, regionY, endpoint),
|
||||
Logger.Log(String.Format("Region {0} online at ({1},{2}) listening on {3}", regionName, regionX, regionY, endpoint),
|
||||
Helpers.LogLevel.Info);
|
||||
|
||||
// Tell the grid that this region is online
|
||||
regionInfo.Online = true;
|
||||
server.Grid.RegionUpdate(regionInfo, regionCert);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChatHandler(Packet packet, Agent agent)
|
||||
{
|
||||
ChatFromViewerPacket chat = (ChatFromViewerPacket)packet;
|
||||
string message = Utils.BytesToString(chat.ChatData.Message);
|
||||
if (message == "lol")
|
||||
SendEvent(agent, "lol", new OSDMap());
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
Logger.Log("Stopping region " + regionName, Helpers.LogLevel.Info);
|
||||
@@ -665,6 +689,7 @@ namespace Simian
|
||||
lock (sceneAgents) sceneAgents[agent.ID] = agent;
|
||||
|
||||
Logger.Log("Added agent " + agent.FullName + " to the scene", Helpers.LogLevel.Info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -942,6 +967,10 @@ namespace Simian
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Capabilities Interfaces
|
||||
|
||||
#region Callback Handlers
|
||||
|
||||
public bool SeedCapabilityHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
|
||||
{
|
||||
UUID agentID = (UUID)state;
|
||||
@@ -987,9 +1016,105 @@ namespace Simian
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Capabilities Interfaces
|
||||
public bool EnableClientCapHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
|
||||
{
|
||||
OSDMap map = OSDParser.DeserializeLLSDXml(request.Body) as OSDMap;
|
||||
OSDMap osdResponse = new OSDMap();
|
||||
|
||||
#region Callback Handlers
|
||||
if (map != null)
|
||||
{
|
||||
UUID agentID = map["agent_id"].AsUUID();
|
||||
UUID sessionID = map["session_id"].AsUUID();
|
||||
UUID secureSessionID = map["secure_session_id"].AsUUID();
|
||||
// TODO: Send an identity url and token instead so we can pull down all of the information
|
||||
string firstName = map["first_name"].AsString();
|
||||
string lastName = map["last_name"].AsString();
|
||||
Uri callbackUri = map["callback_uri"].AsUri();
|
||||
|
||||
Logger.Log(String.Format(
|
||||
"enable_client request. agent_id: {0}, session_id: {1}, secureSessionID: {2}, " +
|
||||
"first_name: {3}, last_name: {4}, callback_uri: {5}", agentID, sessionID, secureSessionID,
|
||||
firstName, lastName, callbackUri), Helpers.LogLevel.Info);
|
||||
|
||||
if (agentID != UUID.Zero && sessionID != UUID.Zero && secureSessionID != UUID.Zero &&
|
||||
!String.IsNullOrEmpty(firstName) && !String.IsNullOrEmpty(lastName))
|
||||
{
|
||||
AgentInfo info = new AgentInfo();
|
||||
info.AccessLevel = "M";
|
||||
info.FirstName = firstName;
|
||||
info.Height = 1.9f;
|
||||
info.HomeLookAt = Vector3.UnitX;
|
||||
info.HomePosition = new Vector3(128f, 128f, 25f);
|
||||
info.HomeRegionHandle = regionHandle;
|
||||
info.ID = agentID;
|
||||
info.LastName = lastName;
|
||||
info.PasswordHash = String.Empty;
|
||||
|
||||
Agent agent = new Agent(new SimulationObject(new Avatar(), this), info);
|
||||
|
||||
// Set the avatar ID
|
||||
agent.Avatar.Prim.ID = agentID;
|
||||
|
||||
// Random session IDs
|
||||
agent.SessionID = sessionID;
|
||||
agent.SecureSessionID = secureSessionID;
|
||||
|
||||
// Create a seed capability for this agent
|
||||
agent.SeedCapability = server.Capabilities.CreateCapability(SeedCapabilityHandler, false, agentID);
|
||||
|
||||
agent.TickLastPacketReceived = Environment.TickCount;
|
||||
agent.Info.LastLoginTime = Utils.DateTimeToUnixTime(DateTime.Now);
|
||||
|
||||
// Add the callback URI to the list of pending enable_client_complete callbacks
|
||||
lock (enableClientCompleteCallbacks)
|
||||
enableClientCompleteCallbacks[agentID] = callbackUri;
|
||||
|
||||
// Assign a circuit code and track the agent as an unassociated agent (no UDP connection yet)
|
||||
agent.CircuitCode = udp.CreateCircuit(agent);
|
||||
|
||||
osdResponse["success"] = OSD.FromBoolean(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
osdResponse["success"] = OSD.FromBoolean(false);
|
||||
osdResponse["message"] = OSD.FromString("missing required fields for enable_client");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
osdResponse["success"] = OSD.FromBoolean(false);
|
||||
osdResponse["message"] = OSD.FromString("failed to parse enable_client message");
|
||||
}
|
||||
|
||||
byte[] responseData = OSDParser.SerializeLLSDXmlBytes(osdResponse);
|
||||
response.ContentLength = responseData.Length;
|
||||
response.Body.Write(responseData, 0, responseData.Length);
|
||||
response.Body.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool EnableClientCompleteCapHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
|
||||
{
|
||||
OSDMap map = OSDParser.DeserializeLLSDXml(request.Body) as OSDMap;
|
||||
OSDMap osdResponse = new OSDMap();
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
UUID agentID = map["agent_id"].AsUUID();
|
||||
Uri seedCapability = map["seed_capability"].AsUri();
|
||||
|
||||
Logger.Log(String.Format("enable_client_complete response. agent_id: {0}, seed_capability: {1}",
|
||||
agentID, seedCapability), Helpers.LogLevel.Info);
|
||||
|
||||
if (enableClientCompleteCallbacks.Remove(agentID))
|
||||
{
|
||||
// FIXME: Finish this
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EventQueueHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
|
||||
{
|
||||
@@ -997,6 +1122,70 @@ namespace Simian
|
||||
return eqServer.EventQueueHandler(context, request, response);
|
||||
}
|
||||
|
||||
void Grid_OnRegionUpdate(RegionInfo regionInfo)
|
||||
{
|
||||
// TODO: Detect regions coming online so we can call
|
||||
// InformClientOfNeighbors(agent);
|
||||
// for every agent
|
||||
|
||||
// Check if the sim was a neighbor
|
||||
if (regionInfo.Handle == Utils.UIntsToLong(256 * (regionX - 1), 256 * (regionY + 1)))
|
||||
neighbors[0] = regionInfo;
|
||||
else if (regionInfo.Handle == Utils.UIntsToLong(256 * regionX, 256 * (regionY + 1)))
|
||||
neighbors[1] = regionInfo;
|
||||
else if (regionInfo.Handle == Utils.UIntsToLong(256 * (regionX + 1), 256 * (regionY + 1)))
|
||||
neighbors[2] = regionInfo;
|
||||
else if (regionInfo.Handle == Utils.UIntsToLong(256 * (regionX - 1), 256 * regionY))
|
||||
neighbors[3] = regionInfo;
|
||||
else if (regionInfo.Handle == Utils.UIntsToLong(256 * (regionX + 1), 256 * regionY))
|
||||
neighbors[4] = regionInfo;
|
||||
else if (regionInfo.Handle == Utils.UIntsToLong(256 * (regionX - 1), 256 * (regionY - 1)))
|
||||
neighbors[5] = regionInfo;
|
||||
else if (regionInfo.Handle == Utils.UIntsToLong(256 * regionX, 256 * (regionY - 1)))
|
||||
neighbors[6] = regionInfo;
|
||||
else if (regionInfo.Handle == Utils.UIntsToLong(256 * (regionX + 1), 256 * (regionY - 1)))
|
||||
neighbors[7] = regionInfo;
|
||||
}
|
||||
|
||||
void udp_OnAgentConnection(Agent agent, uint circuitCode)
|
||||
{
|
||||
Uri callbackUri;
|
||||
if (enableClientCompleteCallbacks.TryGetValue(agent.ID, out callbackUri))
|
||||
{
|
||||
lock (enableClientCompleteCallbacks)
|
||||
enableClientCompleteCallbacks.Remove(agent.ID);
|
||||
|
||||
Logger.Log("Sending enable_client_complete callback to " + callbackUri.ToString(), Helpers.LogLevel.Info);
|
||||
|
||||
OSDMap map = new OSDMap(1);
|
||||
map["agent_id"] = OSD.FromUUID(agent.ID);
|
||||
|
||||
AutoResetEvent waitEvent = new AutoResetEvent(false);
|
||||
|
||||
CapsClient request = new CapsClient(callbackUri);
|
||||
request.OnComplete +=
|
||||
delegate(CapsClient client, OSD result, Exception error)
|
||||
{
|
||||
OSDMap response = result as OSDMap;
|
||||
if (response != null)
|
||||
{
|
||||
bool success = response["success"].AsBoolean();
|
||||
Logger.Log("enable_client_complete response: " + success, Helpers.LogLevel.Info);
|
||||
|
||||
if (success)
|
||||
{
|
||||
Uri seedCapability = response["seed_capability"].AsUri();
|
||||
}
|
||||
}
|
||||
waitEvent.Set();
|
||||
};
|
||||
request.StartRequest(map);
|
||||
|
||||
if (!waitEvent.WaitOne(30 * 1000, false))
|
||||
Logger.Log("enable_client_complete request timed out", Helpers.LogLevel.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
void CompleteAgentMovementHandler(Packet packet, Agent agent)
|
||||
{
|
||||
// Add this avatar as an object in the scene
|
||||
@@ -1006,7 +1195,7 @@ namespace Simian
|
||||
AgentMovementCompletePacket complete = new AgentMovementCompletePacket();
|
||||
complete.AgentData.AgentID = agent.ID;
|
||||
complete.AgentData.SessionID = agent.SessionID;
|
||||
complete.Data.LookAt = Vector3.UnitX;
|
||||
complete.Data.LookAt = Vector3.UnitX; // TODO: Properly implement LookAt someday
|
||||
complete.Data.Position = agent.Avatar.Prim.Position;
|
||||
complete.Data.RegionHandle = regionHandle;
|
||||
complete.Data.Timestamp = Utils.DateTimeToUnixTime(DateTime.Now);
|
||||
@@ -1023,10 +1212,72 @@ namespace Simian
|
||||
online.AgentBlock[0] = new OnlineNotificationPacket.AgentBlockBlock();
|
||||
online.AgentBlock[0].AgentID = agent.ID;
|
||||
udp.BroadcastPacket(online, PacketCategory.State);
|
||||
|
||||
// Initiate the connection process for this agent to neighboring regions
|
||||
InformClientOfNeighbors(agent);
|
||||
}
|
||||
|
||||
#endregion Callback Handlers
|
||||
|
||||
void InformClientOfNeighbors(Agent agent)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (!agent.NeighborConnections[i] && neighbors[i].Online)
|
||||
{
|
||||
Logger.Log("Sending enable_client for " + agent.FullName + " to neighbor " + neighbors[i].Name, Helpers.LogLevel.Info);
|
||||
|
||||
// Create a callback for enable_client_complete
|
||||
Uri callbackUri = server.Capabilities.CreateCapability(EnableClientCompleteCapHandler, false, null);
|
||||
|
||||
OSDMap map = new OSDMap();
|
||||
map["agent_id"] = OSD.FromUUID(agent.ID);
|
||||
map["session_id"] = OSD.FromUUID(agent.SessionID);
|
||||
map["secure_session_id"] = OSD.FromUUID(agent.SecureSessionID);
|
||||
map["first_name"] = OSD.FromString(agent.Info.FirstName);
|
||||
map["last_name"] = OSD.FromString(agent.Info.LastName);
|
||||
map["callback_uri"] = OSD.FromUri(callbackUri);
|
||||
|
||||
AutoResetEvent waitEvent = new AutoResetEvent(false);
|
||||
|
||||
CapsClient request = new CapsClient(neighbors[i].EnableClientCap);
|
||||
request.OnComplete +=
|
||||
delegate(CapsClient client, OSD result, Exception error)
|
||||
{
|
||||
OSDMap response = result as OSDMap;
|
||||
if (response != null)
|
||||
{
|
||||
bool success = response["success"].AsBoolean();
|
||||
Logger.Log("enable_client response: " + success, Helpers.LogLevel.Info);
|
||||
|
||||
if (success)
|
||||
{
|
||||
// Send the EnableSimulator capability to clients
|
||||
OSDMap llsdSimInfo = new OSDMap(3);
|
||||
|
||||
llsdSimInfo.Add("Handle", OSD.FromULong(neighbors[i].Handle));
|
||||
llsdSimInfo.Add("IP", OSD.FromBinary(neighbors[i].IPAndPort.Address.GetAddressBytes()));
|
||||
llsdSimInfo.Add("Port", OSD.FromInteger(neighbors[i].IPAndPort.Port));
|
||||
|
||||
OSDArray arr = new OSDArray(1);
|
||||
arr.Add(llsdSimInfo);
|
||||
|
||||
OSDMap llsdBody = new OSDMap(1);
|
||||
llsdBody.Add("SimulatorInfo", arr);
|
||||
|
||||
SendEvent(agent, "EnableSimulator", llsdBody);
|
||||
}
|
||||
}
|
||||
waitEvent.Set();
|
||||
};
|
||||
request.StartRequest(map);
|
||||
|
||||
if (!waitEvent.WaitOne(30 * 1000, false))
|
||||
Logger.Log("enable_client request timed out", Helpers.LogLevel.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: The reduction provider will deprecate this at some point
|
||||
void SynchronizeStateTo(Agent agent)
|
||||
{
|
||||
@@ -1452,7 +1703,7 @@ namespace Simian
|
||||
{
|
||||
#region ImprovedTerseObjectUpdate
|
||||
|
||||
Logger.DebugLog("Sending ImprovedTerseObjectUpdate");
|
||||
//Logger.DebugLog("Sending ImprovedTerseObjectUpdate");
|
||||
|
||||
int pos = 0;
|
||||
byte[] data = new byte[(obj.Prim is Avatar ? 60 : 44)];
|
||||
|
||||
Reference in New Issue
Block a user