/*
* Copyright (c) 2006-2014, openmetaverse.org
* 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.
* - Neither the name of the openmetaverse.org 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.Text;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Http;
using OpenMetaverse.Packets;
namespace OpenMetaverse
{
#region Enums
///
/// Map layer request type
///
public enum GridLayerType : uint
{
/// Objects and terrain are shown
Objects = 0,
/// Only the terrain is shown, no objects
Terrain = 1,
/// Overlay showing land for sale and for auction
LandForSale = 2
}
///
/// Type of grid item, such as telehub, event, populator location, etc.
///
public enum GridItemType : uint
{
/// Telehub
Telehub = 1,
/// PG rated event
PgEvent = 2,
/// Mature rated event
MatureEvent = 3,
/// Popular location
Popular = 4,
/// Locations of avatar groups in a region
AgentLocations = 6,
/// Land for sale
LandForSale = 7,
/// Classified ad
Classified = 8,
/// Adult rated event
AdultEvent = 9,
/// Adult land for sale
AdultLandForSale = 10
}
#endregion Enums
#region Structs
///
/// Information about a region on the grid map
///
public struct GridRegion
{
/// Sim X position on World Map
public int X;
/// Sim Y position on World Map
public int Y;
/// Sim Name (NOTE: In lowercase!)
public string Name;
///
public SimAccess Access;
/// Appears to always be zero (None)
public RegionFlags RegionFlags;
/// Sim's defined Water Height
public byte WaterHeight;
///
public byte Agents;
/// UUID of the World Map image
public UUID MapImageID;
/// Unique identifier for this region, a combination of the X
/// and Y position
public ulong RegionHandle;
///
///
///
///
public override string ToString()
{
return String.Format("{0} ({1}/{2}), Handle: {3}, MapImage: {4}, Access: {5}, Flags: {6}",
Name, X, Y, RegionHandle, MapImageID, Access, RegionFlags);
}
///
///
///
///
public override int GetHashCode()
{
return X.GetHashCode() ^ Y.GetHashCode();
}
///
///
///
///
///
public override bool Equals(object obj)
{
if (obj is GridRegion)
return Equals((GridRegion)obj);
else
return false;
}
private bool Equals(GridRegion region)
{
return (this.X == region.X && this.Y == region.Y);
}
}
///
/// Visual chunk of the grid map
///
public struct GridLayer
{
public int Bottom;
public int Left;
public int Top;
public int Right;
public UUID ImageID;
public bool ContainsRegion(int x, int y)
{
return (x >= Left && x <= Right && y >= Bottom && y <= Top);
}
}
#endregion Structs
#region Map Item Classes
///
/// Base class for Map Items
///
public abstract class MapItem
{
/// The Global X position of the item
public uint GlobalX;
/// The Global Y position of the item
public uint GlobalY;
/// Get the Local X position of the item
public uint LocalX { get { return GlobalX % 256; } }
/// Get the Local Y position of the item
public uint LocalY { get { return GlobalY % 256; } }
/// Get the Handle of the region
public ulong RegionHandle
{
get { return Utils.UIntsToLong((uint)(GlobalX - (GlobalX % 256)), (uint)(GlobalY - (GlobalY % 256))); }
}
}
///
/// Represents an agent or group of agents location
///
public class MapAgentLocation : MapItem
{
public int AvatarCount;
public string Identifier;
}
///
/// Represents a Telehub location
///
public class MapTelehub : MapItem
{
}
///
/// Represents a non-adult parcel of land for sale
///
public class MapLandForSale : MapItem
{
public int Size;
public int Price;
public string Name;
public UUID ID;
}
///
/// Represents an Adult parcel of land for sale
///
public class MapAdultLandForSale : MapItem
{
public int Size;
public int Price;
public string Name;
public UUID ID;
}
///
/// Represents a PG Event
///
public class MapPGEvent : MapItem
{
public DirectoryManager.EventFlags Flags; // Extra
public DirectoryManager.EventCategories Category; // Extra2
public string Description;
}
///
/// Represents a Mature event
///
public class MapMatureEvent : MapItem
{
public DirectoryManager.EventFlags Flags; // Extra
public DirectoryManager.EventCategories Category; // Extra2
public string Description;
}
///
/// Represents an Adult event
///
public class MapAdultEvent : MapItem
{
public DirectoryManager.EventFlags Flags; // Extra
public DirectoryManager.EventCategories Category; // Extra2
public string Description;
}
#endregion Grid Item Classes
///
/// Manages grid-wide tasks such as the world map
///
public class GridManager
{
#region Delegates
/// The event subscribers. null if no subcribers
private EventHandler m_CoarseLocationUpdate;
/// Raises the CoarseLocationUpdate event
/// A CoarseLocationUpdateEventArgs object containing the
/// data sent by simulator
protected virtual void OnCoarseLocationUpdate(CoarseLocationUpdateEventArgs e)
{
EventHandler handler = m_CoarseLocationUpdate;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_CoarseLocationUpdateLock = new object();
/// Raised when the simulator sends a
/// containing the location of agents in the simulator
public event EventHandler CoarseLocationUpdate
{
add { lock (m_CoarseLocationUpdateLock) { m_CoarseLocationUpdate += value; } }
remove { lock (m_CoarseLocationUpdateLock) { m_CoarseLocationUpdate -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_GridRegion;
/// Raises the GridRegion event
/// A GridRegionEventArgs object containing the
/// data sent by simulator
protected virtual void OnGridRegion(GridRegionEventArgs e)
{
EventHandler handler = m_GridRegion;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_GridRegionLock = new object();
/// Raised when the simulator sends a Region Data in response to
/// a Map request
public event EventHandler GridRegion
{
add { lock (m_GridRegionLock) { m_GridRegion += value; } }
remove { lock (m_GridRegionLock) { m_GridRegion -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_GridLayer;
/// Raises the GridLayer event
/// A GridLayerEventArgs object containing the
/// data sent by simulator
protected virtual void OnGridLayer(GridLayerEventArgs e)
{
EventHandler handler = m_GridLayer;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_GridLayerLock = new object();
/// Raised when the simulator sends GridLayer object containing
/// a map tile coordinates and texture information
public event EventHandler GridLayer
{
add { lock (m_GridLayerLock) { m_GridLayer += value; } }
remove { lock (m_GridLayerLock) { m_GridLayer -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_GridItems;
/// Raises the GridItems event
/// A GridItemEventArgs object containing the
/// data sent by simulator
protected virtual void OnGridItems(GridItemsEventArgs e)
{
EventHandler handler = m_GridItems;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_GridItemsLock = new object();
/// Raised when the simulator sends GridItems object containing
/// details on events, land sales at a specific location
public event EventHandler GridItems
{
add { lock (m_GridItemsLock) { m_GridItems += value; } }
remove { lock (m_GridItemsLock) { m_GridItems -= value; } }
}
/// The event subscribers. null if no subcribers
private EventHandler m_RegionHandleReply;
/// Raises the RegionHandleReply event
/// A RegionHandleReplyEventArgs object containing the
/// data sent by simulator
protected virtual void OnRegionHandleReply(RegionHandleReplyEventArgs e)
{
EventHandler handler = m_RegionHandleReply;
if (handler != null)
handler(this, e);
}
/// Thread sync lock object
private readonly object m_RegionHandleReplyLock = new object();
/// Raised in response to a Region lookup
public event EventHandler RegionHandleReply
{
add { lock (m_RegionHandleReplyLock) { m_RegionHandleReply += value; } }
remove { lock (m_RegionHandleReplyLock) { m_RegionHandleReply -= value; } }
}
#endregion Delegates
/// Unknown
public float SunPhase { get { return sunPhase; } }
/// Current direction of the sun
public Vector3 SunDirection { get { return sunDirection; } }
/// Current angular velocity of the sun
public Vector3 SunAngVelocity { get { return sunAngVelocity; } }
/// Microseconds since the start of SL 4-hour day
public ulong TimeOfDay { get { return timeOfDay; } }
/// A dictionary of all the regions, indexed by region name
internal Dictionary Regions = new Dictionary();
/// A dictionary of all the regions, indexed by region handle
internal Dictionary RegionsByHandle = new Dictionary();
private GridClient Client;
private float sunPhase;
private Vector3 sunDirection;
private Vector3 sunAngVelocity;
private ulong timeOfDay;
///
/// Constructor
///
/// Instance of GridClient object to associate with this GridManager instance
public GridManager(GridClient client)
{
Client = client;
//Client.Network.RegisterCallback(PacketType.MapLayerReply, MapLayerReplyHandler);
Client.Network.RegisterCallback(PacketType.MapBlockReply, MapBlockReplyHandler);
Client.Network.RegisterCallback(PacketType.MapItemReply, MapItemReplyHandler);
Client.Network.RegisterCallback(PacketType.SimulatorViewerTimeMessage, SimulatorViewerTimeMessageHandler);
Client.Network.RegisterCallback(PacketType.CoarseLocationUpdate, CoarseLocationHandler, false);
Client.Network.RegisterCallback(PacketType.RegionIDAndHandleReply, RegionHandleReplyHandler);
}
///
///
///
///
public void RequestMapLayer(GridLayerType layer)
{
Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("MapLayer");
if (url != null)
{
OSDMap body = new OSDMap();
body["Flags"] = OSD.FromInteger((int)layer);
CapsClient request = new CapsClient(url);
request.OnComplete += new CapsClient.CompleteCallback(MapLayerResponseHandler);
request.BeginGetResponse(body, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
}
}
///
/// Request a map layer
///
/// The name of the region
/// The type of layer
public void RequestMapRegion(string regionName, GridLayerType layer)
{
MapNameRequestPacket request = new MapNameRequestPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.AgentData.Flags = (uint)layer;
request.AgentData.EstateID = 0; // Filled in on the sim
request.AgentData.Godlike = false; // Filled in on the sim
request.NameData.Name = Utils.StringToBytes(regionName);
Client.Network.SendPacket(request);
}
///
///
///
///
///
///
///
///
///
public void RequestMapBlocks(GridLayerType layer, ushort minX, ushort minY, ushort maxX, ushort maxY,
bool returnNonExistent)
{
MapBlockRequestPacket request = new MapBlockRequestPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.AgentData.Flags = (uint)layer;
request.AgentData.Flags |= (uint)(returnNonExistent ? 0x10000 : 0);
request.AgentData.EstateID = 0; // Filled in at the simulator
request.AgentData.Godlike = false; // Filled in at the simulator
request.PositionData.MinX = minX;
request.PositionData.MinY = minY;
request.PositionData.MaxX = maxX;
request.PositionData.MaxY = maxY;
Client.Network.SendPacket(request);
}
///
///
///
///
///
///
///
///
public List MapItems(ulong regionHandle, GridItemType item, GridLayerType layer, int timeoutMS)
{
List itemList = null;
AutoResetEvent itemsEvent = new AutoResetEvent(false);
EventHandler callback =
delegate(object sender, GridItemsEventArgs e)
{
if (e.Type == GridItemType.AgentLocations)
{
itemList = e.Items;
itemsEvent.Set();
}
};
GridItems += callback;
RequestMapItems(regionHandle, item, layer);
itemsEvent.WaitOne(timeoutMS, false);
GridItems -= callback;
return itemList;
}
///
///
///
///
///
///
public void RequestMapItems(ulong regionHandle, GridItemType item, GridLayerType layer)
{
MapItemRequestPacket request = new MapItemRequestPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.AgentData.Flags = (uint)layer;
request.AgentData.Godlike = false; // Filled in on the sim
request.AgentData.EstateID = 0; // Filled in on the sim
request.RequestData.ItemType = (uint)item;
request.RequestData.RegionHandle = regionHandle;
Client.Network.SendPacket(request);
}
///
/// Request data for all mainland (Linden managed) simulators
///
public void RequestMainlandSims(GridLayerType layer)
{
RequestMapBlocks(layer, 0, 0, 65535, 65535, false);
}
///
/// Request the region handle for the specified region UUID
///
/// UUID of the region to look up
public void RequestRegionHandle(UUID regionID)
{
RegionHandleRequestPacket request = new RegionHandleRequestPacket();
request.RequestBlock = new RegionHandleRequestPacket.RequestBlockBlock();
request.RequestBlock.RegionID = regionID;
Client.Network.SendPacket(request);
}
///
/// Get grid region information using the region name, this function
/// will block until it can find the region or gives up
///
/// Name of sim you're looking for
/// Layer that you are requesting
/// Will contain a GridRegion for the sim you're
/// looking for if successful, otherwise an empty structure
/// True if the GridRegion was successfully fetched, otherwise
/// false
public bool GetGridRegion(string name, GridLayerType layer, out GridRegion region)
{
if (String.IsNullOrEmpty(name))
{
Logger.Log("GetGridRegion called with a null or empty region name", Helpers.LogLevel.Error, Client);
region = new GridRegion();
return false;
}
if (Regions.ContainsKey(name))
{
// We already have this GridRegion structure
region = Regions[name];
return true;
}
else
{
AutoResetEvent regionEvent = new AutoResetEvent(false);
EventHandler callback =
delegate(object sender, GridRegionEventArgs e)
{
if (e.Region.Name == name)
regionEvent.Set();
};
GridRegion += callback;
RequestMapRegion(name, layer);
regionEvent.WaitOne(Client.Settings.MAP_REQUEST_TIMEOUT, false);
GridRegion -= callback;
if (Regions.ContainsKey(name))
{
// The region was found after our request
region = Regions[name];
return true;
}
else
{
Logger.Log("Couldn't find region " + name, Helpers.LogLevel.Warning, Client);
region = new GridRegion();
return false;
}
}
}
protected void MapLayerResponseHandler(CapsClient client, OSD result, Exception error)
{
if (result == null)
{
Logger.Log("MapLayerResponseHandler error: " + error.Message + ": " + error.StackTrace, Helpers.LogLevel.Error, Client);
return;
}
OSDMap body = (OSDMap)result;
OSDArray layerData = (OSDArray)body["LayerData"];
if (m_GridLayer != null)
{
for (int i = 0; i < layerData.Count; i++)
{
OSDMap thisLayerData = (OSDMap)layerData[i];
GridLayer layer;
layer.Bottom = thisLayerData["Bottom"].AsInteger();
layer.Left = thisLayerData["Left"].AsInteger();
layer.Top = thisLayerData["Top"].AsInteger();
layer.Right = thisLayerData["Right"].AsInteger();
layer.ImageID = thisLayerData["ImageID"].AsUUID();
OnGridLayer(new GridLayerEventArgs(layer));
}
}
if (body.ContainsKey("MapBlocks"))
{
// TODO: At one point this will become activated
Logger.Log("Got MapBlocks through CAPS, please finish this function!", Helpers.LogLevel.Error, Client);
}
}
/// Process an incoming packet and raise the appropriate events
/// The sender
/// The EventArgs object containing the packet data
protected void MapBlockReplyHandler(object sender, PacketReceivedEventArgs e)
{
MapBlockReplyPacket map = (MapBlockReplyPacket)e.Packet;
foreach (MapBlockReplyPacket.DataBlock block in map.Data)
{
if (block.X != 0 || block.Y != 0)
{
GridRegion region;
region.X = block.X;
region.Y = block.Y;
region.Name = Utils.BytesToString(block.Name);
// RegionFlags seems to always be zero here?
region.RegionFlags = (RegionFlags)block.RegionFlags;
region.WaterHeight = block.WaterHeight;
region.Agents = block.Agents;
region.Access = (SimAccess)block.Access;
region.MapImageID = block.MapImageID;
region.RegionHandle = Utils.UIntsToLong((uint)(region.X * 256), (uint)(region.Y * 256));
lock (Regions)
{
Regions[region.Name] = region;
RegionsByHandle[region.RegionHandle] = region;
}
if (m_GridRegion != null)
{
OnGridRegion(new GridRegionEventArgs(region));
}
}
}
}
/// Process an incoming packet and raise the appropriate events
/// The sender
/// The EventArgs object containing the packet data
protected void MapItemReplyHandler(object sender, PacketReceivedEventArgs e)
{
if (m_GridItems != null)
{
MapItemReplyPacket reply = (MapItemReplyPacket)e.Packet;
GridItemType type = (GridItemType)reply.RequestData.ItemType;
List items = new List();
for (int i = 0; i < reply.Data.Length; i++)
{
string name = Utils.BytesToString(reply.Data[i].Name);
switch (type)
{
case GridItemType.AgentLocations:
MapAgentLocation location = new MapAgentLocation();
location.GlobalX = reply.Data[i].X;
location.GlobalY = reply.Data[i].Y;
location.Identifier = name;
location.AvatarCount = reply.Data[i].Extra;
items.Add(location);
break;
case GridItemType.Classified:
//FIXME:
Logger.Log("FIXME", Helpers.LogLevel.Error, Client);
break;
case GridItemType.LandForSale:
MapLandForSale landsale = new MapLandForSale();
landsale.GlobalX = reply.Data[i].X;
landsale.GlobalY = reply.Data[i].Y;
landsale.ID = reply.Data[i].ID;
landsale.Name = name;
landsale.Size = reply.Data[i].Extra;
landsale.Price = reply.Data[i].Extra2;
items.Add(landsale);
break;
case GridItemType.MatureEvent:
MapMatureEvent matureEvent = new MapMatureEvent();
matureEvent.GlobalX = reply.Data[i].X;
matureEvent.GlobalY = reply.Data[i].Y;
matureEvent.Description = name;
matureEvent.Flags = (DirectoryManager.EventFlags)reply.Data[i].Extra2;
items.Add(matureEvent);
break;
case GridItemType.PgEvent:
MapPGEvent PGEvent = new MapPGEvent();
PGEvent.GlobalX = reply.Data[i].X;
PGEvent.GlobalY = reply.Data[i].Y;
PGEvent.Description = name;
PGEvent.Flags = (DirectoryManager.EventFlags)reply.Data[i].Extra2;
items.Add(PGEvent);
break;
case GridItemType.Popular:
//FIXME:
Logger.Log("FIXME", Helpers.LogLevel.Error, Client);
break;
case GridItemType.Telehub:
MapTelehub teleHubItem = new MapTelehub();
teleHubItem.GlobalX = reply.Data[i].X;
teleHubItem.GlobalY = reply.Data[i].Y;
items.Add(teleHubItem);
break;
case GridItemType.AdultLandForSale:
MapAdultLandForSale adultLandsale = new MapAdultLandForSale();
adultLandsale.GlobalX = reply.Data[i].X;
adultLandsale.GlobalY = reply.Data[i].Y;
adultLandsale.ID = reply.Data[i].ID;
adultLandsale.Name = name;
adultLandsale.Size = reply.Data[i].Extra;
adultLandsale.Price = reply.Data[i].Extra2;
items.Add(adultLandsale);
break;
case GridItemType.AdultEvent:
MapAdultEvent adultEvent = new MapAdultEvent();
adultEvent.GlobalX = reply.Data[i].X;
adultEvent.GlobalY = reply.Data[i].Y;
adultEvent.Description = Utils.BytesToString(reply.Data[i].Name);
adultEvent.Flags = (DirectoryManager.EventFlags)reply.Data[i].Extra2;
items.Add(adultEvent);
break;
default:
Logger.Log("Unknown map item type " + type, Helpers.LogLevel.Warning, Client);
break;
}
}
OnGridItems(new GridItemsEventArgs(type, items));
}
}
/// Process an incoming packet and raise the appropriate events
/// The sender
/// The EventArgs object containing the packet data
protected void SimulatorViewerTimeMessageHandler(object sender, PacketReceivedEventArgs e)
{
SimulatorViewerTimeMessagePacket time = (SimulatorViewerTimeMessagePacket)e.Packet;
sunPhase = time.TimeInfo.SunPhase;
sunDirection = time.TimeInfo.SunDirection;
sunAngVelocity = time.TimeInfo.SunAngVelocity;
timeOfDay = time.TimeInfo.UsecSinceStart;
// TODO: Does anyone have a use for the time stuff?
}
/// Process an incoming packet and raise the appropriate events
/// The sender
/// The EventArgs object containing the packet data
protected void CoarseLocationHandler(object sender, PacketReceivedEventArgs e)
{
CoarseLocationUpdatePacket coarse = (CoarseLocationUpdatePacket)e.Packet;
// populate a dictionary from the packet, for local use
Dictionary coarseEntries = new Dictionary();
for (int i = 0; i < coarse.AgentData.Length; i++)
{
if(coarse.Location.Length > 0)
coarseEntries[coarse.AgentData[i].AgentID] = new Vector3((int)coarse.Location[i].X, (int)coarse.Location[i].Y, (int)coarse.Location[i].Z * 4);
// the friend we are tracking on radar
if (i == coarse.Index.Prey)
e.Simulator.preyID = coarse.AgentData[i].AgentID;
}
// find stale entries (people who left the sim)
List removedEntries = e.Simulator.avatarPositions.FindAll(delegate(UUID findID) { return !coarseEntries.ContainsKey(findID); });
// anyone who was not listed in the previous update
List newEntries = new List();
lock (e.Simulator.avatarPositions.Dictionary)
{
// remove stale entries
foreach(UUID trackedID in removedEntries)
e.Simulator.avatarPositions.Dictionary.Remove(trackedID);
// add or update tracked info, and record who is new
foreach (KeyValuePair entry in coarseEntries)
{
if (!e.Simulator.avatarPositions.Dictionary.ContainsKey(entry.Key))
newEntries.Add(entry.Key);
e.Simulator.avatarPositions.Dictionary[entry.Key] = entry.Value;
}
}
if (m_CoarseLocationUpdate != null)
{
WorkPool.QueueUserWorkItem(delegate(object o)
{ OnCoarseLocationUpdate(new CoarseLocationUpdateEventArgs(e.Simulator, newEntries, removedEntries)); });
}
}
/// Process an incoming packet and raise the appropriate events
/// The sender
/// The EventArgs object containing the packet data
protected void RegionHandleReplyHandler(object sender, PacketReceivedEventArgs e)
{
if (m_RegionHandleReply != null)
{
RegionIDAndHandleReplyPacket reply = (RegionIDAndHandleReplyPacket)e.Packet;
OnRegionHandleReply(new RegionHandleReplyEventArgs(reply.ReplyBlock.RegionID, reply.ReplyBlock.RegionHandle));
}
}
}
#region EventArgs classes
public class CoarseLocationUpdateEventArgs : EventArgs
{
private readonly Simulator m_Simulator;
private readonly List m_NewEntries;
private readonly List m_RemovedEntries;
public Simulator Simulator { get { return m_Simulator; } }
public List NewEntries { get { return m_NewEntries; } }
public List RemovedEntries { get { return m_RemovedEntries; } }
public CoarseLocationUpdateEventArgs(Simulator simulator, List newEntries, List removedEntries)
{
this.m_Simulator = simulator;
this.m_NewEntries = newEntries;
this.m_RemovedEntries = removedEntries;
}
}
public class GridRegionEventArgs : EventArgs
{
private readonly GridRegion m_Region;
public GridRegion Region { get { return m_Region; } }
public GridRegionEventArgs(GridRegion region)
{
this.m_Region = region;
}
}
public class GridLayerEventArgs : EventArgs
{
private readonly GridLayer m_Layer;
public GridLayer Layer { get { return m_Layer; } }
public GridLayerEventArgs(GridLayer layer)
{
this.m_Layer = layer;
}
}
public class GridItemsEventArgs : EventArgs
{
private readonly GridItemType m_Type;
private readonly List m_Items;
public GridItemType Type { get { return m_Type; } }
public List Items { get { return m_Items; } }
public GridItemsEventArgs(GridItemType type, List items)
{
this.m_Type = type;
this.m_Items = items;
}
}
public class RegionHandleReplyEventArgs : EventArgs
{
private readonly UUID m_RegionID;
private readonly ulong m_RegionHandle;
public UUID RegionID { get { return m_RegionID; } }
public ulong RegionHandle { get { return m_RegionHandle; } }
public RegionHandleReplyEventArgs(UUID regionID, ulong regionHandle)
{
this.m_RegionID = regionID;
this.m_RegionHandle = regionHandle;
}
}
#endregion
}