Package com.ngt.jopenmetaverse.shared.sim

Source Code of com.ngt.jopenmetaverse.shared.sim.GridManager

/**
* A library to interact with Virtual Worlds such as OpenSim
* Copyright (C) 2012  Jitendra Chauhan, Email: jitendra.chauhan@gmail.com
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.ngt.jopenmetaverse.shared.sim;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URI;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Observable;
import com.ngt.jopenmetaverse.shared.cap.http.CapsHttpClient;
import com.ngt.jopenmetaverse.shared.cap.http.CapsHttpRequestCompletedArg;
import com.ngt.jopenmetaverse.shared.protocol.CoarseLocationUpdatePacket;
import com.ngt.jopenmetaverse.shared.protocol.MapBlockReplyPacket;
import com.ngt.jopenmetaverse.shared.protocol.MapBlockRequestPacket;
import com.ngt.jopenmetaverse.shared.protocol.MapItemReplyPacket;
import com.ngt.jopenmetaverse.shared.protocol.MapItemRequestPacket;
import com.ngt.jopenmetaverse.shared.protocol.MapNameRequestPacket;
import com.ngt.jopenmetaverse.shared.protocol.PacketType;
import com.ngt.jopenmetaverse.shared.protocol.RegionHandleRequestPacket;
import com.ngt.jopenmetaverse.shared.protocol.RegionIDAndHandleReplyPacket;
import com.ngt.jopenmetaverse.shared.protocol.SimulatorViewerTimeMessagePacket;
import com.ngt.jopenmetaverse.shared.sim.Simulator.RegionFlags;
import com.ngt.jopenmetaverse.shared.sim.Simulator.SimAccess;
import com.ngt.jopenmetaverse.shared.sim.events.AutoResetEvent;
import com.ngt.jopenmetaverse.shared.sim.events.EventObservable;
import com.ngt.jopenmetaverse.shared.sim.events.EventObserver;
import com.ngt.jopenmetaverse.shared.sim.events.PacketReceivedEventArgs;
import com.ngt.jopenmetaverse.shared.sim.events.ThreadPool;
import com.ngt.jopenmetaverse.shared.sim.events.ThreadPoolFactory;
import com.ngt.jopenmetaverse.shared.sim.events.gm.CoarseLocationUpdateEventArgs;
import com.ngt.jopenmetaverse.shared.sim.events.gm.GridItemsEventArgs;
import com.ngt.jopenmetaverse.shared.sim.events.gm.GridLayerEventArgs;
import com.ngt.jopenmetaverse.shared.sim.events.gm.GridRegionEventArgs;
import com.ngt.jopenmetaverse.shared.sim.events.gm.RegionHandleReplyEventArgs;
import com.ngt.jopenmetaverse.shared.structureddata.OSD;
import com.ngt.jopenmetaverse.shared.structureddata.OSDArray;
import com.ngt.jopenmetaverse.shared.structureddata.OSDFormat;
import com.ngt.jopenmetaverse.shared.structureddata.OSDMap;
import com.ngt.jopenmetaverse.shared.types.UUID;
import com.ngt.jopenmetaverse.shared.types.Vector3;
import com.ngt.jopenmetaverse.shared.util.JLogger;
import com.ngt.jopenmetaverse.shared.util.Utils;

/// <summary>
/// Manages grid-wide tasks such as the world map
/// </summary>
public class GridManager {
  //region Enums

  /// <summary>
  /// Map layer request type
  /// </summary>
  public enum GridLayerType
  {
    //uint
    /// <summary>Objects and terrain are shown</summary>
    Objects(0),
    /// <summary>Only the terrain is shown, no objects</summary>
    Terrain(1),
    /// <summary>Overlay showing land for sale and for auction</summary>
    LandForSale(2);
    private long index;
    GridLayerType(long index)
    {
      this.index = index;
    }    

    public long getIndex()
    {
      return index;
   

    //    private static final Map<Long,GridLayerType> lookup  = new HashMap<Long,GridLayerType>();
    //
    //    static {
    //      for(GridLayerType s : EnumSet.allOf(GridLayerType.class))
    //        lookup.put(s.getIndex(), s);
    //    }
    //
    //    public static GridLayerType get(Long index)
    //    {
    //      return lookup.get(index);
    //    }
  }

  /// <summary>
  /// Type of grid item, such as telehub, event, populator location, etc.
  /// </summary>
  public enum GridItemType
  {
    //uint
    /// <summary>Telehub</summary>
    Telehub(1),
    /// <summary>PG rated event</summary>
    PgEvent(2),
    /// <summary>Mature rated event</summary>
    MatureEvent(3),
    /// <summary>Popular location</summary>
    Popular(4),
    /// <summary>Locations of avatar groups in a region</summary>
    AgentLocations(6),
    /// <summary>Land for sale</summary>
    LandForSale(7),
    /// <summary>Classified ad</summary>
    Classified(8),
    /// <summary>Adult rated event</summary>
    AdultEvent(9),
    /// <summary>Adult land for sale</summary>
    AdultLandForSale(10);
    private long index;
    GridItemType(long index)
    {
      this.index = index;
    }    

    public long getIndex()
    {
      return index;
   

    private static final Map<Long,GridItemType> lookup  = new HashMap<Long,GridItemType>();

    static {
      for(GridItemType s : EnumSet.allOf(GridItemType.class))
        lookup.put(s.getIndex(), s);
    }

    public static GridItemType get(Long index)
    {
      return lookup.get(index);
    }
  }

  //endregion Enums

  //region Structs

  /// <summary>
  /// Information about a region on the grid map
  /// </summary>
  public class GridRegion
  {
    /// <summary>Sim X position on World Map</summary>
    public int X;
    /// <summary>Sim Y position on World Map</summary>
    public int Y;
    /// <summary>Sim Name (NOTE: In lowercase!)</summary>
    public String Name;
    /// <summary></summary>
    public SimAccess Access;
    /// <summary>Appears to always be zero (None)</summary>
    public EnumSet<RegionFlags> RegionFlags;
    /// <summary>Sim's defined Water Height</summary>
    public byte WaterHeight;
    /// <summary></summary>
    public byte Agents;
    /// <summary>UUID of the World Map image</summary>
    public UUID MapImageID;
    /// <summary>Unique identifier for this region, a combination of the X
    /// and Y position</summary>
    //ulong
    public BigInteger RegionHandle;


    /// <summary>
    ///
    /// </summary>
    /// <returns></returns>
    @Override
    public String toString()
    {
      return String.format("%s (%d/%d), Handle: %s, MapImage: %s, Access: %s, Flags: %s",
          Name, X, Y, RegionHandle.toString(), MapImageID.toString(), Access.toString(), RegionFlags.toString());
    }

    /// <summary>
    ///
    /// </summary>
    /// <returns></returns>
    @Override
    public int hashCode()
    {
      return (new Integer(X)).hashCode() ^ (new Integer(Y)).hashCode();
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    @Override
    public boolean equals(Object obj)
    {
      if (obj instanceof GridRegion)
        return equals((GridRegion)obj);
      else
        return false;
    }

    private boolean equals(GridRegion region)
    {
      return (this.X == region.X && this.Y == region.Y);
    }
  }

  /// <summary>
  /// Visual chunk of the grid map
  /// </summary>
  public class GridLayer
  {
    public int Bottom;
    public int Left;
    public int Top;
    public int Right;
    public UUID ImageID;

    public boolean containsRegion(int x, int y)
    {
      return (x >= Left && x <= Right && y >= Bottom && y <= Top);
    }
  }

  //endregion Structs

  //region Map Item Classes

  /// <summary>
  /// Base class for Map Items
  /// </summary>
  public abstract class MapItem
  {
    /// <summary>The Global X position of the item</summary>
    //uint
    public long GlobalX;
    /// <summary>The Global Y position of the item</summary>
    //uint
    public long GlobalY;

    /// <summary>Get the Local X position of the item</summary>
    //uint
    public long getLocalX() { return GlobalX % 256; }
    /// <summary>Get the Local Y position of the item</summary>
    //uint
    public long getLocalY() { return GlobalY % 256; }

    /// <summary>Get the Handle of the region</summary>
    //ulong
    public BigInteger getRegionHandle()
    {
      return Utils.uintsToULong((long)(GlobalX - (GlobalX % 256)), (long)(GlobalY - (GlobalY % 256)));
    }
  }

  /// <summary>
  /// Represents an agent or group of agents location
  /// </summary>
  public class MapAgentLocation extends MapItem
  {      
    public int AvatarCount;
    public String Identifier;
  }

  /// <summary>
  /// Represents a Telehub location
  /// </summary>
  public class MapTelehub extends MapItem
  {       
  }

  /// <summary>
  /// Represents a non-adult parcel of land for sale
  /// </summary>
  public class MapLandForSale extends MapItem
  {       
    public int Size;
    public int Price;
    public String Name;
    public UUID ID;       
  }

  /// <summary>
  /// Represents an Adult parcel of land for sale
  /// </summary>
  public class MapAdultLandForSale extends MapItem
  {    
    public int Size;
    public int Price;
    public String Name;
    public UUID ID;
  }

  /// <summary>
  /// Represents a PG Event
  /// </summary>
  public class MapPGEvent extends MapItem
  {
    public DirectoryManager.EventFlags Flags; // Extra
    public DirectoryManager.EventCategories Category; // Extra2
    public String Description;
  }

  /// <summary>
  /// Represents a Mature event
  /// </summary>
  public class MapMatureEvent extends  MapItem
  {
    public DirectoryManager.EventFlags Flags; // Extra
    public DirectoryManager.EventCategories Category; // Extra2
    public String Description;
  }

  /// <summary>
  /// Represents an Adult event
  /// </summary>
  public class MapAdultEvent extends  MapItem
  {
    public DirectoryManager.EventFlags Flags; // Extra
    public DirectoryManager.EventCategories Category; // Extra2
    public String Description;
  }
  //endregion Grid Item Classes

  private EventObservable<CoarseLocationUpdateEventArgs> OnCoarseLocationUpdate = new EventObservable<CoarseLocationUpdateEventArgs>();
  private EventObservable<GridRegionEventArgs> OnGridRegion = new EventObservable<GridRegionEventArgs>();
  private EventObservable<GridLayerEventArgs> OnGridLayer = new EventObservable<GridLayerEventArgs>();
  private EventObservable<GridItemsEventArgs> OnGridItems = new EventObservable<GridItemsEventArgs>();
  private EventObservable<RegionHandleReplyEventArgs> OnRegionHandleReply = new EventObservable<RegionHandleReplyEventArgs>();

  public void registerOnCoarseLocationUpdate(EventObserver<CoarseLocationUpdateEventArgs> o)
  {
    OnCoarseLocationUpdate.addObserver(o);
  }

  public void unregisterOnCoarseLocationUpdate(EventObserver<CoarseLocationUpdateEventArgs> o)
  {
    OnCoarseLocationUpdate.deleteObserver(o);
  }

  public void registerOnGridRegion(EventObserver<GridRegionEventArgs> o)
  {
    OnGridRegion.addObserver(o);
  }

  public void unregisterOnGridRegion(EventObserver<GridRegionEventArgs> o)
  {
    OnGridRegion.deleteObserver(o);
  }

  public void registerOnGridLayer(EventObserver<GridLayerEventArgs> o)
  {
    OnGridLayer.addObserver(o);
  }

  public void unregisterOnGridLayer(EventObserver<GridLayerEventArgs> o)
  {
    OnGridLayer.deleteObserver(o);
  }

  public void registerOnGridItems(EventObserver<GridItemsEventArgs> o)
  {
    OnGridItems.addObserver(o);
  }

  public void unregisterOnGridItems(EventObserver<GridItemsEventArgs> o)
  {
    OnGridItems.deleteObserver(o);
  }

  public void registerOnRegionHandleReply(EventObserver<RegionHandleReplyEventArgs> o)
  {
    OnRegionHandleReply.addObserver(o);
  }

  public void unregisterOnRegionHandleReply(EventObserver<RegionHandleReplyEventArgs> o)
  {
    OnRegionHandleReply.deleteObserver(o);
  }


  //        //region Delegates
  //
  //        /// <summary>The event subscribers. null if no subcribers</summary>
  //        private EventHandler<CoarseLocationUpdateEventArgs> m_CoarseLocationUpdate;
  //
  //        /// <summary>Raises the CoarseLocationUpdate event</summary>
  //        /// <param name="e">A CoarseLocationUpdateEventArgs object containing the
  //        /// data sent by simulator</param>
  //        protected virtual void OnCoarseLocationUpdate(CoarseLocationUpdateEventArgs e)
  //        {
  //            EventHandler<CoarseLocationUpdateEventArgs> handler = m_CoarseLocationUpdate;
  //            if (handler != null)
  //                handler(this, e);
  //        }
  //
  //        /// <summary>Thread sync lock object</summary>
  //        private readonly object m_CoarseLocationUpdateLock = new object();
  //
  //        /// <summary>Raised when the simulator sends a <see cref="CoarseLocationUpdatePacket"/>
  //        /// containing the location of agents in the simulator</summary>
  //        public event EventHandler<CoarseLocationUpdateEventArgs> CoarseLocationUpdate
  //        {
  //            add { lock (m_CoarseLocationUpdateLock) { m_CoarseLocationUpdate += value; } }
  //            remove { lock (m_CoarseLocationUpdateLock) { m_CoarseLocationUpdate -= value; } }
  //        }
  //
  //        /// <summary>The event subscribers. null if no subcribers</summary>
  //        private EventHandler<GridRegionEventArgs> m_GridRegion;
  //
  //        /// <summary>Raises the GridRegion event</summary>
  //        /// <param name="e">A GridRegionEventArgs object containing the
  //        /// data sent by simulator</param>
  //        protected virtual void OnGridRegion(GridRegionEventArgs e)
  //        {
  //            EventHandler<GridRegionEventArgs> handler = m_GridRegion;
  //            if (handler != null)
  //                handler(this, e);
  //        }
  //
  //        /// <summary>Thread sync lock object</summary>
  //        private readonly object m_GridRegionLock = new object();
  //
  //        /// <summary>Raised when the simulator sends a Region Data in response to
  //        /// a Map request</summary>
  //        public event EventHandler<GridRegionEventArgs> GridRegion
  //        {
  //            add { lock (m_GridRegionLock) { m_GridRegion += value; } }
  //            remove { lock (m_GridRegionLock) { m_GridRegion -= value; } }
  //        }
  //
  //        /// <summary>The event subscribers. null if no subcribers</summary>
  //        private EventHandler<GridLayerEventArgs> m_GridLayer;
  //
  //        /// <summary>Raises the GridLayer event</summary>
  //        /// <param name="e">A GridLayerEventArgs object containing the
  //        /// data sent by simulator</param>
  //        protected virtual void OnGridLayer(GridLayerEventArgs e)
  //        {
  //            EventHandler<GridLayerEventArgs> handler = m_GridLayer;
  //            if (handler != null)
  //                handler(this, e);
  //        }
  //
  //        /// <summary>Thread sync lock object</summary>
  //        private readonly object m_GridLayerLock = new object();
  //
  //        /// <summary>Raised when the simulator sends GridLayer object containing
  //        /// a map tile coordinates and texture information</summary>
  //        public event EventHandler<GridLayerEventArgs> GridLayer
  //        {
  //            add { lock (m_GridLayerLock) { m_GridLayer += value; } }
  //            remove { lock (m_GridLayerLock) { m_GridLayer -= value; } }
  //        }
  //
  //        /// <summary>The event subscribers. null if no subcribers</summary>
  //        private EventHandler<GridItemsEventArgs> m_GridItems;
  //
  //        /// <summary>Raises the GridItems event</summary>
  //        /// <param name="e">A GridItemEventArgs object containing the
  //        /// data sent by simulator</param>
  //        protected virtual void OnGridItems(GridItemsEventArgs e)
  //        {
  //            EventHandler<GridItemsEventArgs> handler = m_GridItems;
  //            if (handler != null)
  //                handler(this, e);
  //        }
  //
  //        /// <summary>Thread sync lock object</summary>
  //        private readonly object m_GridItemsLock = new object();
  //
  //        /// <summary>Raised when the simulator sends GridItems object containing
  //        /// details on events, land sales at a specific location</summary>
  //        public event EventHandler<GridItemsEventArgs> GridItems
  //        {
  //            add { lock (m_GridItemsLock) { m_GridItems += value; } }
  //            remove { lock (m_GridItemsLock) { m_GridItems -= value; } }
  //        }
  //
  //        /// <summary>The event subscribers. null if no subcribers</summary>
  //        private EventHandler<RegionHandleReplyEventArgs> m_RegionHandleReply;
  //
  //        /// <summary>Raises the RegionHandleReply event</summary>
  //        /// <param name="e">A RegionHandleReplyEventArgs object containing the
  //        /// data sent by simulator</param>
  //        protected virtual void OnRegionHandleReply(RegionHandleReplyEventArgs e)
  //        {
  //            EventHandler<RegionHandleReplyEventArgs> handler = m_RegionHandleReply;
  //            if (handler != null)
  //                handler(this, e);
  //        }
  //
  //        /// <summary>Thread sync lock object</summary>
  //        private readonly object m_RegionHandleReplyLock = new object();
  //
  //        /// <summary>Raised in response to a Region lookup</summary>
  //        public event EventHandler<RegionHandleReplyEventArgs> RegionHandleReply
  //        {
  //            add { lock (m_RegionHandleReplyLock) { m_RegionHandleReply += value; } }
  //            remove { lock (m_RegionHandleReplyLock) { m_RegionHandleReply -= value; } }
  //        }
  //
  //        //endregion Delegates

  private static ThreadPool threadPool = ThreadPoolFactory.getThreadPool();

  /// <summary>Unknown</summary>
  public float getSunPhase() {  return sunPhase; }
  /// <summary>Current direction of the sun</summary>
  public Vector3 getSunDirection() { return sunDirection; }
  /// <summary>Current angular velocity of the sun</summary>
  public Vector3 getSunAngVelocity() {  return sunAngVelocity; }
  /// <summary>Microseconds since the start of SL 4-hour day</summary>
  //ulong
  public long getTimeOfDay() { return timeOfDay; }

  /// <summary>A dictionary of all the regions, indexed by region name</summary>
  public Map<String, GridRegion> Regions = new HashMap<String, GridRegion>();
  /// <summary>A dictionary of all the regions, indexed by region handle</summary>
  //<BigInteger, GridRegion>
  public Map<BigInteger, GridRegion> RegionsByHandle = new HashMap<BigInteger, GridRegion>();

  private GridClient Client;
  private float sunPhase;
  private Vector3 sunDirection;
  private Vector3 sunAngVelocity;
  private long timeOfDay;

  /// <summary>
  /// Constructor
  /// </summary>
  /// <param name="client">Instance of GridClient object to associate with this GridManager instance</param>
  public GridManager(GridClient client)
  {
    Client = client;

    //            //Client.Network.RegisterCallback(PacketType.MapLayerReply, MapLayerReplyHandler);
    //            Client.network.RegisterCallback(PacketType.MapBlockReply, MapBlockReplyHandler);
    Client.network.RegisterCallback(PacketType.MapBlockReply,
        new EventObserver<PacketReceivedEventArgs>()
        {
      @Override
      public void handleEvent(Observable o,
          PacketReceivedEventArgs arg) {
        try{ MapBlockReplyHandler(o, arg);}
        catch(Exception e) {JLogger.warn(Utils.getExceptionStackTraceAsString(e));}
      }});

    //            Client.network.RegisterCallback(PacketType.MapItemReply, MapItemReplyHandler);
    Client.network.RegisterCallback(PacketType.MapItemReply,
        new EventObserver<PacketReceivedEventArgs>()
        {
      @Override
      public void handleEvent(Observable o,
          PacketReceivedEventArgs arg) {
        try{MapItemReplyHandler(o, arg);}
        catch(Exception e) {JLogger.warn(Utils.getExceptionStackTraceAsString(e));}

      }}
        );

    //            Client.network.RegisterCallback(PacketType.SimulatorViewerTimeMessage, SimulatorViewerTimeMessageHandler);
    Client.network.RegisterCallback(PacketType.SimulatorViewerTimeMessage,  new EventObserver<PacketReceivedEventArgs>()
        {
      @Override
      public void handleEvent(Observable o,
          PacketReceivedEventArgs arg) {
        try{SimulatorViewerTimeMessageHandler(o, arg);}
        catch(Exception e) {JLogger.warn(Utils.getExceptionStackTraceAsString(e));}

      }});

    //            Client.network.RegisterCallback(PacketType.CoarseLocationUpdate, CoarseLocationHandler, false);
    Client.network.RegisterCallback(PacketType.CoarseLocationUpdate,
        new EventObserver<PacketReceivedEventArgs>()
        {
      @Override
      public void handleEvent(Observable o,
          PacketReceivedEventArgs arg) {
        try{CoarseLocationHandler(o, arg);}
        catch(Exception e) {JLogger.warn(Utils.getExceptionStackTraceAsString(e));}

      }} 
    , false);

    //            Client.network.RegisterCallback(PacketType.RegionIDAndHandleReply, RegionHandleReplyHandler);
    Client.network.RegisterCallback(PacketType.RegionIDAndHandleReply,
        new EventObserver<PacketReceivedEventArgs>()
        {
      @Override
      public void handleEvent(Observable o,
          PacketReceivedEventArgs arg) {
        try{RegionHandleReplyHandler(o, arg);}
        catch(Exception e) {JLogger.warn(Utils.getExceptionStackTraceAsString(e));}

      }} 
        );

  }

  /// <summary>
  ///
  /// </summary>
  /// <param name="layer"></param>
  public void RequestMapLayer(GridLayerType layer) throws Exception
  {
    URI url = Client.network.getCurrentSim().Caps.CapabilityURI("MapLayer");

    if (url != null)
    {
      OSDMap body = new OSDMap();
      body.put("Flags", OSD.FromInteger((int)layer.getIndex()));

      CapsHttpClient request = new CapsHttpClient(url);
      //                request.OnComplete += new CapsHttpClient.CompleteCallback(MapLayerResponseHandler);
      request.addRequestCompleteObserver(new EventObserver<CapsHttpRequestCompletedArg>(){
        @Override
        public void handleEvent(Observable o,
            CapsHttpRequestCompletedArg arg) {
          MapLayerResponseHandler(arg.getClient(), arg.getResult(), arg.getError());
        }
      });
      request.BeginGetResponse(body, OSDFormat.Xml, Client.settings.CAPS_TIMEOUT);
    }
  }

  /// <summary>
  /// Request a map layer
  /// </summary>
  /// <param name="regionName">The name of the region</param>
  /// <param name="layer">The type of layer</param>
  public void RequestMapRegion(String regionName, GridLayerType layer)
  {
    MapNameRequestPacket request = new MapNameRequestPacket();

    request.AgentData.AgentID = Client.self.getAgentID();
    request.AgentData.SessionID = Client.self.getSessionID();
    request.AgentData.Flags = layer.getIndex();
    request.AgentData.EstateID = 0; // Filled in on the sim
    request.AgentData.Godlike = false; // Filled in on the sim
    request.NameData.Name = Utils.stringToBytesWithTrailingNullByte(regionName);

    Client.network.SendPacket(request);
  }

  /// <summary>
  ///
  /// </summary>
  /// <param name="layer"></param>
  /// <param name="minX"></param>
  /// <param name="minY"></param>
  /// <param name="maxX"></param>
  /// <param name="maxY"></param>
  /// <param name="returnNonExistent"></param>
  public void RequestMapBlocks(GridLayerType layer, int minX, int minY, int maxX, int maxY, boolean returnNonExistent)
  {
    MapBlockRequestPacket request = new MapBlockRequestPacket();

    request.AgentData.AgentID = Client.self.getAgentID();
    request.AgentData.SessionID = Client.self.getSessionID();
    request.AgentData.Flags = layer.getIndex();
    request.AgentData.Flags |= (long)(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);
  }

  /// <summary>
  ///
  /// </summary>
  /// <param name="regionHandle"></param>
  /// <param name="item"></param>
  /// <param name="layer"></param>
  /// <param name="timeoutMS"></param>
  /// <returns></returns>
  public List<MapItem> MapItems(BigInteger regionHandle, GridItemType item, GridLayerType layer, int timeoutMS) throws InterruptedException
  {
    List<MapItem> itemList = null;
    final AutoResetEvent itemsEvent = new AutoResetEvent(false);

    //            EventHandler<GridItemsEventArgs> callback =
    //                delegate(Object sender, GridItemsEventArgs e)
    //                {
    //                    if (e.Type == GridItemType.AgentLocations)
    //                    {
    //                        itemList = e.Items;
    //                        itemsEvent.Set();
    //                    }
    //                };
    //
    //            GridItems += callback;
    //
    //            RequestMapItems(regionHandle, item, layer);

    final Object[] itemListArray = new Object[]{null}
    EventObserver<GridItemsEventArgs> callback = new EventObserver<GridItemsEventArgs>()
        {
      @Override
      public void handleEvent(Observable o, GridItemsEventArgs e) {
        if (e.getType().equals(GridItemType.AgentLocations))
        {
          itemListArray[0] = e.getItems();
          itemsEvent.set();
        }} 
        };
        itemList = (List<MapItem>)itemListArray[0];

        OnGridItems.addObserver(callback);
        RequestMapItems(regionHandle, item, layer);

        itemsEvent.waitOne(timeoutMS);

        OnGridItems.deleteObserver(callback);

        return itemList;
  }

  /// <summary>
  ///
  /// </summary>
  /// <param name="regionHandle"></param>
  /// <param name="item"></param>
  /// <param name="layer"></param>
  public void RequestMapItems(BigInteger regionHandle, GridItemType item, GridLayerType layer)
  {
    MapItemRequestPacket request = new MapItemRequestPacket();
    request.AgentData.AgentID = Client.self.getAgentID();
    request.AgentData.SessionID = Client.self.getSessionID();
    request.AgentData.Flags = layer.getIndex();
    request.AgentData.Godlike = false; // Filled in on the sim
    request.AgentData.EstateID = 0; // Filled in on the sim

    request.RequestData.ItemType = item.getIndex();
    request.RequestData.RegionHandle = regionHandle;

    Client.network.SendPacket(request);
  }

  /// <summary>
  /// Request data for all mainland (Linden managed) simulators
  /// </summary>
  public void RequestMainlandSims(GridLayerType layer)
  {
    RequestMapBlocks(layer, 0, 0, 65535, 65535, false);
  }

  /// <summary>
  /// Request the region handle for the specified region UUID
  /// </summary>
  /// <param name="regionID">UUID of the region to look up</param>
  public void RequestRegionHandle(UUID regionID)
  {
    RegionHandleRequestPacket request = new RegionHandleRequestPacket();
    request.RequestBlock = new RegionHandleRequestPacket.RequestBlockBlock();
    request.RequestBlock.RegionID = regionID;
    Client.network.SendPacket(request);
  }

  /// <summary>
  /// Get grid region information using the region name, this function
  /// will block until it can find the region or gives up
  /// </summary>
  /// <param name="name">Name of sim you're looking for</param>
  /// <param name="layer">Layer that you are requesting</param>
  /// <param name="region">Will contain a GridRegion for the sim you're
  /// looking for if successful, otherwise an empty structure</param>
  /// <returns>True if the GridRegion was successfully fetched, otherwise
  /// false</returns>
  public boolean GetGridRegion(final String name, GridLayerType layer, GridRegion[] region) throws InterruptedException
  {
    if (Utils.isNullOrEmpty(name))
    {
      JLogger.error("GetGridRegion called with a null or empty region name");
      region[0] = new GridRegion();
      return false;
    }

    if (Regions.containsKey(name))
    {
      // We already have this GridRegion structure
      region[0] = Regions.get(name);
      return true;
    }
    else
    {
      final AutoResetEvent regionEvent = new AutoResetEvent(false);

      EventObserver<GridRegionEventArgs> callback = new EventObserver<GridRegionEventArgs>()
          { @Override
        public void handleEvent(Observable o, GridRegionEventArgs e)
          {
            if (e.getRegion().Name.equals(name))
              regionEvent.set();
          }
          };

          OnGridRegion.addObserver(callback);

          RequestMapRegion(name, layer);
          regionEvent.waitOne(Client.settings.MAP_REQUEST_TIMEOUT);

          OnGridRegion.deleteObserver(callback);

          if (Regions.containsKey(name))
          {
            // The region was found after our request
            region[0] = Regions.get(name);
            return true;
          }
          else
          {
            JLogger.warn("Couldn't find region " + name);
            region[0] = new GridRegion();
            return false;
          }


          //      EventHandler<GridRegionEventArgs> 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(CapsHttpClient client, OSD result, Exception error)
  {
    OSDMap body = (OSDMap)result;
    OSDArray layerData = (OSDArray)body.get("LayerData");

    if (OnGridLayer != null)
    {
      for (int i = 0; i < layerData.count(); i++)
      {
        OSDMap thisLayerData = (OSDMap)layerData.get(i);

        GridLayer layer = new GridLayer();
        layer.Bottom = thisLayerData.get("Bottom").asInteger();
        layer.Left = thisLayerData.get("Left").asInteger();
        layer.Top = thisLayerData.get("Top").asInteger();
        layer.Right = thisLayerData.get("Right").asInteger();
        layer.ImageID = thisLayerData.get("ImageID").asUUID();

        OnGridLayer.raiseEvent((new GridLayerEventArgs(layer)));                   
      }
    }

    if (body.containsKey("MapBlocks"))
    {
      // TODO: At one point this will become activated
      JLogger.error("Got MapBlocks through CAPS, please finish this function!");
    }
  }

  /// <summary>Process an incoming packet and raise the appropriate events</summary>
  /// <param name="sender">The sender</param>
  /// <param name="e">The EventArgs object containing the packet data</param>
  protected void MapBlockReplyHandler(Object sender, PacketReceivedEventArgs e) throws UnsupportedEncodingException
  {
    MapBlockReplyPacket map = (MapBlockReplyPacket)e.getPacket();

    for (MapBlockReplyPacket.DataBlock block :map.Data)
    {
      if (block.X != 0 && block.Y != 0)
      {
        GridRegion region = new GridRegion();

        region.X = block.X;
        region.Y = block.Y;
        region.Name = Utils.bytesWithTrailingNullByteToString(block.Name);
        // RegionFlags seems to always be zero here?
        region.RegionFlags = RegionFlags.get((int)block.RegionFlags);
        region.WaterHeight = block.WaterHeight;
        region.Agents = block.Agents;
        region.Access = SimAccess.get((short)block.Access);
        region.MapImageID = block.MapImageID;
        region.RegionHandle = Utils.uintsToULong(((long)region.X * 256), ((long)region.Y * 256));

        synchronized (Regions)
        {
          Regions.put(region.Name,  region);
          RegionsByHandle.put(region.RegionHandle, region);
        }

        if (OnGridRegion != null)
        {
          OnGridRegion.raiseEvent((new GridRegionEventArgs(region)));
        }
      }
    }
  }

  /// <summary>Process an incoming packet and raise the appropriate events</summary>
  /// <param name="sender">The sender</param>
  /// <param name="e">The EventArgs object containing the packet data</param>
  protected void MapItemReplyHandler(Object sender, PacketReceivedEventArgs e) throws UnsupportedEncodingException
  {
    if (OnGridItems != null)
    {
      MapItemReplyPacket reply = (MapItemReplyPacket)e.getPacket();
      GridItemType type = GridItemType.get((reply.RequestData.ItemType));
      List<MapItem> items = new ArrayList<MapItem>();

      for (int i = 0; i < reply.Data.length; i++)
      {
        String name = Utils.bytesWithTrailingNullByteToString(reply.Data[i].Name);

        switch (type)
        {
        case 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 Classified:
          //FIXME:
          JLogger.error("FIXME");
          break;
        case 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 MatureEvent:
          MapMatureEvent matureEvent = new MapMatureEvent();
          matureEvent.GlobalX = reply.Data[i].X;
          matureEvent.GlobalY = reply.Data[i].Y;
          matureEvent.Description = name;
          matureEvent.Flags = DirectoryManager.EventFlags.get(reply.Data[i].Extra2);
          items.add(matureEvent);
          break;
        case PgEvent:
          MapPGEvent PGEvent = new MapPGEvent();
          PGEvent.GlobalX = reply.Data[i].X;
          PGEvent.GlobalY = reply.Data[i].Y;
          PGEvent.Description = name;
          PGEvent.Flags = DirectoryManager.EventFlags.get(reply.Data[i].Extra2);
          items.add(PGEvent);
          break;
        case Popular:
          //FIXME:
          JLogger.error("FIXME");
          break;
        case Telehub:
          MapTelehub teleHubItem = new MapTelehub();
          teleHubItem.GlobalX = reply.Data[i].X;
          teleHubItem.GlobalY = reply.Data[i].Y;
          items.add(teleHubItem);
          break;
        case 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 AdultEvent:
          MapAdultEvent adultEvent = new MapAdultEvent();
          adultEvent.GlobalX = reply.Data[i].X;
          adultEvent.GlobalY = reply.Data[i].Y;
          adultEvent.Description = Utils.bytesWithTrailingNullByteToString(reply.Data[i].Name);
          adultEvent.Flags = DirectoryManager.EventFlags.get(reply.Data[i].Extra2);
          items.add(adultEvent);
          break;
        default:
          JLogger.warn("Unknown map item type " + type);
          break;
        }
      }

      OnGridItems.raiseEvent((new GridItemsEventArgs(type, items)));
    }
  }

  /// <summary>Process an incoming packet and raise the appropriate events</summary>
  /// <param name="sender">The sender</param>
  /// <param name="e">The EventArgs object containing the packet data</param>
  protected void SimulatorViewerTimeMessageHandler(Object sender, final PacketReceivedEventArgs e)
  {
    SimulatorViewerTimeMessagePacket time = (SimulatorViewerTimeMessagePacket)e.getPacket();

    sunPhase = time.TimeInfo.SunPhase;
    sunDirection = time.TimeInfo.SunDirection;
    sunAngVelocity = time.TimeInfo.SunAngVelocity;
    timeOfDay = time.TimeInfo.UsecSinceStart.longValue();
    // TODO: Does anyone have a use for the time stuff?
  }

  /// <summary>Process an incoming packet and raise the appropriate events</summary>
  /// <param name="sender">The sender</param>
  /// <param name="e">The EventArgs object containing the packet data</param>
  protected void CoarseLocationHandler(Object sender, final PacketReceivedEventArgs e)
  {
    CoarseLocationUpdatePacket coarse = (CoarseLocationUpdatePacket)e.getPacket();

    // populate a dictionary from the packet, for local use
    Map<UUID, Vector3> coarseEntries = new HashMap<UUID, Vector3>();
    for (int i = 0; i < coarse.AgentData.length; i++)
    {
      if(coarse.Location.length > 0)
        coarseEntries.put(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.getSimulator().preyID = coarse.AgentData[i].AgentID;
    }

    // find stale entries (people who left the sim)
    final List<UUID> removedEntries = new ArrayList<UUID>();
    for(Entry<UUID, Vector3> entry: e.getSimulator().avatarPositions.getDictionary().entrySet())
    {
      if(!coarseEntries.containsKey(entry.getKey()))
      {
        removedEntries.add(entry.getKey());
      }
    }

    //    FindAll(delegate(UUID findID) { return !coarseEntries.ContainsKey(findID); });

    // anyone who was not listed in the previous update
    final List<UUID> newEntries = new ArrayList<UUID>();

    synchronized (e.getSimulator().avatarPositions.getDictionary())
    {
      // remove stale entries
      for(UUID trackedID :removedEntries)
        e.getSimulator().avatarPositions.remove(trackedID);

      // add or update tracked info, and record who is new
      for (Entry<UUID, Vector3> entry : coarseEntries.entrySet())
      {
        if (!e.getSimulator().avatarPositions.containsKey(entry.getKey()))
          newEntries.add(entry.getKey());

        e.getSimulator().avatarPositions.add(entry.getKey(), entry.getValue());
      }
    }

    if (OnCoarseLocationUpdate != null)
    {
      threadPool.execute(new Runnable(){
        public void run()
        {
          OnCoarseLocationUpdate.raiseEvent(
              (new CoarseLocationUpdateEventArgs(e.getSimulator(),
                  newEntries, removedEntries)));
        }
      });
      //      ThreadPool.QueueUserWorkItem(delegate(object o)
      //          { OnCoarseLocationUpdate(new CoarseLocationUpdateEventArgs(e.getSimulator(), newEntries, removedEntries)); });
    }
  }

  /// <summary>Process an incoming packet and raise the appropriate events</summary>
  /// <param name="sender">The sender</param>
  /// <param name="e">The EventArgs object containing the packet data</param>
  protected void RegionHandleReplyHandler(Object sender, PacketReceivedEventArgs e)
  {           
    if (OnRegionHandleReply != null)
    {
      RegionIDAndHandleReplyPacket reply = (RegionIDAndHandleReplyPacket)e.getPacket();
      OnRegionHandleReply.raiseEvent(new RegionHandleReplyEventArgs(reply.ReplyBlock.RegionID, reply.ReplyBlock.RegionHandle));
    }
  }
  //endregion
}
TOP

Related Classes of com.ngt.jopenmetaverse.shared.sim.GridManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.