protected override void GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { List<MapBlockData> mapBlocks = new List<MapBlockData>(); List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, minX * (int)Constants.RegionSize, maxX * (int)Constants.RegionSize, minY * (int)Constants.RegionSize, maxY * (int)Constants.RegionSize); foreach (GridRegion r in regions) { MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r); mapBlocks.Add(block); } // Different from super FillInMap(mapBlocks, minX, minY, maxX, maxY); // remoteClient.SendMapBlock(mapBlocks, 0); }
private void FillInMap(List<MapBlockData> mapBlocks, int minX, int minY, int maxX, int maxY) { for (int x = minX; x <= maxX; x++) { for (int y = minY; y <= maxY; y++) { MapBlockData mblock = mapBlocks.Find(delegate(MapBlockData mb) { return ((mb.X == x) && (mb.Y == y)); }); if (mblock == null) { mblock = new MapBlockData(); mblock.X = (ushort)x; mblock.Y = (ushort)y; mblock.Name = ""; mblock.Access = 254; // not here??? mblock.MapImageId = UUID.Zero; mapBlocks.Add(mblock); } } } }
private void OnMapNameRequest (IClientAPI remoteClient, string mapName, uint flags) { if (mapName.Length < 1) { remoteClient.SendAlertMessage("Use a search string with at least 1 character"); return; } bool TryCoordsSearch = false; int XCoord = 0; int YCoord = 0; string[] splitSearch = mapName.Split(','); if (splitSearch.Length != 1) { if (splitSearch[1].StartsWith (" ")) splitSearch[1] = splitSearch[1].Remove (0, 1); if (int.TryParse(splitSearch[0], out XCoord) && int.TryParse(splitSearch[1], out YCoord)) TryCoordsSearch = true; } List<MapBlockData> blocks = new List<MapBlockData>(); List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(UUID.Zero, mapName, 20); if (TryCoordsSearch) { GridRegion region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)(XCoord * Constants.RegionSize), (int)(YCoord * Constants.RegionSize)); if (region != null) { region.RegionName = mapName + " - " + region.RegionName; regionInfos.Add (region); } } List<GridRegion> allRegions = new List<GridRegion> (); foreach (GridRegion region in regionInfos) { //Add the found in search region first if (!allRegions.Contains (region)) { allRegions.Add (region); blocks.Add (SearchMapBlockFromGridRegion (region)); } //Then send surrounding regions List<GridRegion> regions = m_scene.GridService.GetRegionRange (m_scene.RegionInfo.ScopeID, (region.RegionLocX - (4 * (int)Constants.RegionSize)), (region.RegionLocX + (4 * (int)Constants.RegionSize)), (region.RegionLocY - (4 * (int)Constants.RegionSize)), (region.RegionLocY + (4 * (int)Constants.RegionSize))); if (regions != null) { foreach (GridRegion r in regions) { if (!allRegions.Contains (region)) { allRegions.Add (region); blocks.Add (SearchMapBlockFromGridRegion (r)); } } } } // final block, closing the search result MapBlockData data = new MapBlockData(); data.Agents = 0; data.Access = 255; data.MapImageID = UUID.Zero; data.Name = mapName; data.RegionFlags = 0; data.WaterHeight = 0; // not used data.X = 0; data.Y = 0; blocks.Add(data); remoteClient.SendMapBlock (blocks, flags); }
/// <summary> /// Export the world map /// </summary> /// <param name="fileName"></param> public void HandleExportWorldMapConsoleCommand(string module, string[] cmdparams) { if (m_scene.ConsoleScene() == null) { // FIXME: If console region is root then this will be printed by every module. Currently, there is no // way to prevent this, short of making the entire module shared (which is complete overkill). // One possibility is to return a bool to signal whether the module has completely handled the command m_log.InfoFormat("[WORLD MAP]: Please change to a specific region in order to export its world map"); return; } if (m_scene.ConsoleScene() != m_scene) return; string exportPath; if (cmdparams.Length > 1) exportPath = cmdparams[1]; else exportPath = DEFAULT_WORLD_MAP_EXPORT_PATH; m_log.InfoFormat( "[WORLD MAP]: Exporting world map for {0} to {1}", m_scene.RegionInfo.RegionName, exportPath); List<MapBlockData> mapBlocks = new List<MapBlockData>(); List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, (int)(m_scene.RegionInfo.RegionLocX - 9) * (int)Constants.RegionSize, (int)(m_scene.RegionInfo.RegionLocX + 9) * (int)Constants.RegionSize, (int)(m_scene.RegionInfo.RegionLocY - 9) * (int)Constants.RegionSize, (int)(m_scene.RegionInfo.RegionLocY + 9) * (int)Constants.RegionSize); List<AssetBase> textures = new List<AssetBase>(); List<Image> bitImages = new List<Image>(); foreach (GridRegion r in regions) { MapBlockData mapBlock = new MapBlockData(); MapBlockFromGridRegion(mapBlock, r); AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString()); if (texAsset != null) { textures.Add(texAsset); } //else //{ // // WHAT?!? This doesn't seem right. Commenting (diva) // texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString()); // if (texAsset != null) // { // textures.Add(texAsset); // } //} } foreach (AssetBase asset in textures) { ManagedImage managedImage; Image image; if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image)) bitImages.Add(image); } Bitmap mapTexture = new Bitmap(2560, 2560); Graphics g = Graphics.FromImage(mapTexture); SolidBrush sea = new SolidBrush(Color.DarkBlue); g.FillRectangle(sea, 0, 0, 2560, 2560); for (int i = 0; i < mapBlocks.Count; i++) { ushort x = (ushort)((mapBlocks[i].X - m_scene.RegionInfo.RegionLocX) + 10); ushort y = (ushort)((mapBlocks[i].Y - m_scene.RegionInfo.RegionLocY) + 10); g.DrawImage(bitImages[i], (x * 128), 2560 - (y * 128), 128, 128); // y origin is top } mapTexture.Save(exportPath, ImageFormat.Jpeg); m_log.InfoFormat( "[WORLD MAP]: Successfully exported world map for {0} to {1}", m_scene.RegionInfo.RegionName, exportPath); }
protected virtual void GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { List<MapBlockData> mapBlocks = new List<MapBlockData>(); List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, (minX - 4) * (int)Constants.RegionSize, (maxX + 4) * (int)Constants.RegionSize, (minY - 4) * (int)Constants.RegionSize, (maxY + 4) * (int)Constants.RegionSize); foreach (GridRegion r in regions) { MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r); mapBlocks.Add(block); } remoteClient.SendMapBlock(mapBlocks, flag); }
/// <summary> /// Callback for a map layer request /// </summary> /// <param name="request"></param> /// <param name="path"></param> /// <param name="param"></param> /// <param name="agentID"></param> /// <param name="caps"></param> /// <returns></returns> public string MapLayerRequest(string request, string path, string param, UUID agentID, Caps caps) { //try //{ //m_log.DebugFormat("[MAPLAYER]: request: {0}, path: {1}, param: {2}, agent:{3}", //request, path, param,agentID.ToString()); // this is here because CAPS map requests work even beyond the 10,000 limit. ScenePresence avatarPresence = null; m_scene.TryGetScenePresence(agentID, out avatarPresence); if (avatarPresence != null) { bool lookup = false; lock (cachedMapBlocks) { if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) { List<MapBlockData> mapBlocks; mapBlocks = cachedMapBlocks; avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); } else { lookup = true; } } if (lookup) { List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); foreach (GridRegion r in regions) { MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r); mapBlocks.Add(block); } avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); lock (cachedMapBlocks) cachedMapBlocks = mapBlocks; cachedTime = Util.UnixTimeSinceEpoch(); } } LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); return mapResponse.ToString(); }
private void RequestNonVisibleMapTile(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { List<MapBlockData> response = new List<MapBlockData>(); // this should return one mapblock at most. But make sure: Look whether the one we requested is in there List<MapBlockData> mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks(minX, minY, maxX, maxY); if (mapBlocks != null) { foreach (MapBlockData block in mapBlocks) { if (block.X == minX && block.Y == minY) { // found it => add it to response response.Add(block); break; } } } if (response.Count == 0) { // response still empty => couldn't find the map-tile the user clicked on => tell the client MapBlockData block = new MapBlockData(); block.X = (ushort)minX; block.Y = (ushort)minY; block.Access = 254; // == not there response.Add(block); } //(flag & 0x10000) != 0 is sent by v2 viewers, and it expects flag 2 back remoteClient.SendMapBlock(response, flag & 0xffff); }
/// <summary> /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates /// </summary> /// <param name="minX"></param> /// <param name="minY"></param> /// <param name="maxX"></param> /// <param name="maxY"></param> public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible { List<MapBlockData> response = new List<MapBlockData>(); // this should return one mapblock at most. It is triggered by a click // on an unloaded square. // But make sure: Look whether the one we requested is in there List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, minX * (int)Constants.RegionSize, maxX * (int)Constants.RegionSize, minY * (int)Constants.RegionSize, maxY * (int)Constants.RegionSize); if (regions != null) { foreach (GridRegion r in regions) { if ((r.RegionLocX == minX * (int)Constants.RegionSize) && (r.RegionLocY == minY * (int)Constants.RegionSize)) { // found it => add it to response MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r, flag); response.Add(block); break; } } } if (response.Count == 0) { // response still empty => couldn't find the map-tile the user clicked on => tell the client MapBlockData block = new MapBlockData(); block.X = (ushort)minX; block.Y = (ushort)minY; block.Access = 254; // means 'simulator is offline' response.Add(block); } // The lower 16 bits are an unsigned int16 remoteClient.SendMapBlock(response, flag & 0xffff); } else { // normal mapblock request. Use the provided values GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); } }
protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag) { block.Access = r.Access; switch (flag & 0xffff) { case 0: block.MapImageId = r.TerrainImage; break; case 2: block.MapImageId = r.ParcelImage; break; default: block.MapImageId = UUID.Zero; break; } block.Name = r.RegionName; block.X = (ushort)(r.RegionLocX / Constants.RegionSize); block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); }
private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) { if (mapName.Length < 3) { remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); return; } //m_log.DebugFormat("MAP NAME=({0})", mapName); // try to fetch from GridServer List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); if (regionInfos.Count == 0) remoteClient.SendAlertMessage("Hyperlink could not be established."); m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags); List<MapBlockData> blocks = new List<MapBlockData>(); MapBlockData data; if (regionInfos.Count > 0) { foreach (GridRegion info in regionInfos) { data = new MapBlockData(); data.Agents = 0; data.Access = info.Access; if (flags == 2) // V2 sends this data.MapImageId = UUID.Zero; else data.MapImageId = info.TerrainImage; data.Name = info.RegionName; data.RegionFlags = 0; // TODO not used? data.WaterHeight = 0; // not used data.X = (ushort)(info.RegionLocX / Constants.RegionSize); data.Y = (ushort)(info.RegionLocY / Constants.RegionSize); blocks.Add(data); } } // final block, closing the search result data = new MapBlockData(); data.Agents = 0; data.Access = 255; data.MapImageId = UUID.Zero; data.Name = ""; // mapName; data.RegionFlags = 0; data.WaterHeight = 0; // not used data.X = 0; data.Y = 0; blocks.Add(data); // flags are agent flags sent from the viewer. // they have different values depending on different viewers, apparently remoteClient.SendMapBlock(blocks, flags); }
private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) { List<MapBlockData> blocks = new List<MapBlockData>(); MapBlockData data; if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4)) { // final block, closing the search result AddFinalBlock(blocks); // flags are agent flags sent from the viewer. // they have different values depending on different viewers, apparently remoteClient.SendMapBlock(blocks, flags); remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); return; } //m_log.DebugFormat("MAP NAME=({0})", mapName); // Hack to get around the fact that ll V3 now drops the port from the // map name. See https://jira.secondlife.com/browse/VWR-28570 // // Caller, use this magic form instead: // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 // or url encode if possible. // the hacks we do with this viewer... // string mapNameOrig = mapName; if (mapName.Contains("|")) mapName = mapName.Replace('|', ':'); if (mapName.Contains("+")) mapName = mapName.Replace('+', ' '); if (mapName.Contains("!")) mapName = mapName.Replace('!', '/'); // try to fetch from GridServer List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags); if (regionInfos.Count > 0) { foreach (GridRegion info in regionInfos) { data = new MapBlockData(); data.Agents = 0; data.Access = info.Access; if (flags == 2) // V2 sends this data.MapImageId = UUID.Zero; else data.MapImageId = info.TerrainImage; // ugh! V2-3 is very sensitive about the result being // exactly the same as the requested name if (regionInfos.Count == 1 && mapNameOrig.Contains("|") || mapNameOrig.Contains("+")) data.Name = mapNameOrig; else data.Name = info.RegionName; data.RegionFlags = 0; // TODO not used? data.WaterHeight = 0; // not used data.X = (ushort)(info.RegionLocX / Constants.RegionSize); data.Y = (ushort)(info.RegionLocY / Constants.RegionSize); blocks.Add(data); } } // final block, closing the search result AddFinalBlock(blocks); // flags are agent flags sent from the viewer. // they have different values depending on different viewers, apparently remoteClient.SendMapBlock(blocks, flags); // send extra user messages for V3 // because the UI is very confusing // while we don't fix the hard-coded urls if (flags == 2) { if (regionInfos.Count == 0) remoteClient.SendAlertMessage("No regions found with that name."); else if (regionInfos.Count == 1) remoteClient.SendAlertMessage("Region found!"); } }
private void FillInMap(List<MapBlockData> mapBlocks, int minX, int minY, int maxX, int maxY) { for (int x = minX; x <= maxX; x++) { for (int y = minY; y <= maxY; y++) { MapBlockData mblock = mapBlocks.Find(delegate(MapBlockData mb) { return ((mb.X == x) && (mb.Y == y)); }); if (mblock == null) { mblock = new MapBlockData(); mblock.X = (ushort)x; mblock.Y = (ushort)y; mblock.Name = ""; mblock.Access = 254; // means 'simulator is offline'. We need this because the viewer ignores 255's mblock.MapImageId = UUID.Zero; mapBlocks.Add(mblock); } } } }
protected override List<MapBlockData> GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { List<MapBlockData> mapBlocks = new List<MapBlockData>(); List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, minX * (int)Constants.RegionSize, maxX * (int)Constants.RegionSize, minY * (int)Constants.RegionSize, maxY * (int)Constants.RegionSize); foreach (GridRegion r in regions) { uint x = 0, y = 0; long handle = 0; if (r.RegionSecret != null && r.RegionSecret != string.Empty) { if (long.TryParse(r.RegionSecret, out handle)) { Utils.LongToUInts((ulong)handle, out x, out y); x = x / Constants.RegionSize; y = y / Constants.RegionSize; } } if (handle == 0 || // Check the distance from the current region (handle != 0 && Math.Abs((int)(x - m_scene.RegionInfo.RegionLocX)) < 4096 && Math.Abs((int)(y - m_scene.RegionInfo.RegionLocY)) < 4096)) { MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r); mapBlocks.Add(block); } } // Different from super FillInMap(mapBlocks, minX, minY, maxX, maxY); // remoteClient.SendMapBlock(mapBlocks, 0); return mapBlocks; }
public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) { if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) return; IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); // Reset animations; the viewer does that in teleports. sp.Animator.ResetAnimations(); try { if (regionHandle == sp.Scene.RegionInfo.RegionHandle) { m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation {0} within {1}", position, sp.Scene.RegionInfo.RegionName); // Teleport within the same region if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) { Vector3 emergencyPos = new Vector3(128, 128, 128); m_log.WarnFormat( "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", position, sp.Name, sp.UUID, emergencyPos); position = emergencyPos; } // TODO: Get proper AVG Height float localAVHeight = 1.56f; float posZLimit = 22; // TODO: Check other Scene HeightField if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) { posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; } float newPosZ = posZLimit + localAVHeight; if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) { position.Z = newPosZ; } // Only send this if the event queue is null if (eq == null) sp.ControllingClient.SendTeleportLocationStart(); sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); sp.Teleport(position); } else // Another region possibly in another simulator { uint x = 0, y = 0; Utils.LongToUInts(regionHandle, out x, out y); GridRegion reg = m_aScene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); if (reg != null) { GridRegion finalDestination = GetFinalDestination(reg); if (finalDestination == null) { m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport agent."); sp.ControllingClient.SendTeleportFailed("Problem at destination"); return; } m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final destination is x={0} y={1} uuid={2}", finalDestination.RegionLocX / Constants.RegionSize, finalDestination.RegionLocY / Constants.RegionSize, finalDestination.RegionID); // // This is it // DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags, eq); // // // } else { // TP to a place that doesn't exist (anymore) // Inform the viewer about that sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); // and set the map-tile to '(Offline)' uint regX, regY; Utils.LongToUInts(regionHandle, out regX, out regY); MapBlockData block = new MapBlockData(); block.X = (ushort)(regX / Constants.RegionSize); block.Y = (ushort)(regY / Constants.RegionSize); block.Access = 254; // == not there List<MapBlockData> blocks = new List<MapBlockData>(); blocks.Add(block); sp.ControllingClient.SendMapBlock(blocks, 0); } } } catch (Exception e) { m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Exception on teleport: {0}\n{1}", e.Message, e.StackTrace); sp.ControllingClient.SendTeleportFailed("Internal error"); } }
/// <summary> /// Teleports the agent to a different region. /// </summary> /// <param name='sp'></param> /// <param name='regionHandle'>/param> /// <param name='position'></param> /// <param name='lookAt'></param> /// <param name='teleportFlags'></param> /// <param name='finalDestination'></param> private void TeleportAgentToDifferentRegion( ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) { uint x = 0, y = 0; Utils.LongToUInts(regionHandle, out x, out y); GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); if (reg != null) { finalDestination = GetFinalDestination(reg); if (finalDestination == null) { m_log.WarnFormat( "[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}", sp.Name, sp.UUID); sp.ControllingClient.SendTeleportFailed("Problem at destination"); return; } // Check that these are not the same coordinates if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX && finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY) { // Can't do. Viewer crashes sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again."); return; } // Validate assorted conditions string reason = string.Empty; if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason)) { sp.ControllingClient.SendTeleportFailed(reason); return; } // // This is it // DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags); // // // } else { finalDestination = null; // TP to a place that doesn't exist (anymore) // Inform the viewer about that sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); // and set the map-tile to '(Offline)' uint regX, regY; Utils.LongToUInts(regionHandle, out regX, out regY); MapBlockData block = new MapBlockData(); block.X = (ushort)(regX / Constants.RegionSize); block.Y = (ushort)(regY / Constants.RegionSize); block.Access = 254; // == not there List<MapBlockData> blocks = new List<MapBlockData>(); blocks.Add(block); sp.ControllingClient.SendMapBlock(blocks, 0); } }
/// <summary> /// Teleports the agent to a different region. /// </summary> /// <param name='sp'></param> /// <param name='regionHandle'>/param> /// <param name='position'></param> /// <param name='lookAt'></param> /// <param name='teleportFlags'></param> /// <param name='finalDestination'></param> private void TeleportAgentToDifferentRegion( ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) { // Get destination region taking into account that the address could be an offset // region inside a varregion. GridRegion reg = GetTeleportDestinationRegion(sp.Scene.GridService, sp.Scene.RegionInfo.ScopeID, regionHandle, ref position); if (reg != null) { string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId); string message; finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out message); if (finalDestination == null) { m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}: {3}", LogHeader, sp.Name, sp.UUID, message); sp.ControllingClient.SendTeleportFailed(message); return; } // Check that these are not the same coordinates if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX && finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY) { // Can't do. Viewer crashes sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again."); return; } // Validate assorted conditions string reason = string.Empty; if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason)) { sp.ControllingClient.SendTeleportFailed(reason); return; } if (message != null) sp.ControllingClient.SendAgentAlertMessage(message, true); // // This is it // DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags); // // // } else { finalDestination = null; // TP to a place that doesn't exist (anymore) // Inform the viewer about that sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); // and set the map-tile to '(Offline)' uint regX, regY; Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY); MapBlockData block = new MapBlockData(); block.X = (ushort)regX; block.Y = (ushort)regY; block.Access = (byte)SimAccess.Down; List<MapBlockData> blocks = new List<MapBlockData>(); blocks.Add(block); sp.ControllingClient.SendMapBlock(blocks, 0); } }
private void AddFinalBlock(List<MapBlockData> blocks) { // final block, closing the search result MapBlockData data = new MapBlockData(); data.Agents = 0; data.Access = (byte)SimAccess.NonExistent; data.MapImageId = UUID.Zero; data.Name = ""; data.RegionFlags = 0; data.WaterHeight = 0; // not used data.X = 0; data.Y = 0; blocks.Add(data); }
public virtual void Teleport(IScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) { int x = 0, y = 0; Util.UlongToInts(regionHandle, out x, out y); GridRegion reg = sp.Scene.GridService.GetRegionByPosition (sp.Scene.RegionInfo.ScopeID, x, y); if (reg == null) { List<GridRegion> regions = sp.Scene.GridService.GetRegionRange (sp.Scene.RegionInfo.ScopeID, x - 8192, x + 8192, y - 8192, y + 8192); foreach (GridRegion r in regions) { if (r.RegionLocX <= x && r.RegionLocX + r.RegionSizeX > x && r.RegionLocY <= y && r.RegionLocY + r.RegionSizeY > y) { reg = r; position.X += x - reg.RegionLocX; position.Y += y - reg.RegionLocY; break; } } if (reg == null) { // TP to a place that doesn't exist (anymore) // Inform the viewer about that sp.ControllingClient.SendTeleportFailed ("The region you tried to teleport to doesn't exist anymore"); // and set the map-tile to '(Offline)' int regX, regY; Util.UlongToInts (regionHandle, out regX, out regY); MapBlockData block = new MapBlockData (); block.X = (ushort)(regX / Constants.RegionSize); block.Y = (ushort)(regY / Constants.RegionSize); block.Access = 254; // == not there List<MapBlockData> blocks = new List<MapBlockData> (); blocks.Add (block); sp.ControllingClient.SendMapBlock (blocks, 0); return; } } Teleport(sp, reg, position, lookAt, teleportFlags); }
/// <summary> /// Callback for a map layer request /// </summary> /// <param name="request"></param> /// <param name="path"></param> /// <param name="param"></param> /// <param name="agentID"></param> /// <param name="caps"></param> /// <returns></returns> public string MapLayerRequest(string request, string path, string param, UUID agentID, Caps caps) { //try // //m_log.DebugFormat("[MAPLAYER]: path: {0}, param: {1}, agent:{2}", // path, param, agentID.ToString()); // There is a major hack going on in this method. The viewer doesn't request // map blocks (RequestMapBlocks) above 2048. That means that if we don't hack, // grids above that cell don't have a map at all. So, here's the hack: we wait // for this CAP request to come, and we inject the map blocks at this point. // In a normal scenario, this request simply sends back the MapLayer (the blue color). // In the hacked scenario, it also sends the map blocks via UDP. // // 6/8/2011 -- I'm adding an explicit 2048 check, so that we never forget that there is // a hack here, and so that regions below 4096 don't get spammed with unnecessary map blocks. if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) { ScenePresence avatarPresence = null; m_scene.TryGetScenePresence(agentID, out avatarPresence); if (avatarPresence != null) { bool lookup = false; lock (cachedMapBlocks) { if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) { List<MapBlockData> mapBlocks; mapBlocks = cachedMapBlocks; avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); } else { lookup = true; } } if (lookup) { List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); foreach (GridRegion r in regions) { MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r, 0); mapBlocks.Add(block); } avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); lock (cachedMapBlocks) cachedMapBlocks = mapBlocks; cachedTime = Util.UnixTimeSinceEpoch(); } } } LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); return mapResponse.ToString(); }
/// <summary> /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates /// </summary> /// <param name="minX"></param> /// <param name="minY"></param> /// <param name="maxX"></param> /// <param name="maxY"></param> public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { if ((flag & 0x10000) != 0) // user clicked on the map a tile that isn't visible { List<MapBlockData> response = new List<MapBlockData>(); // this should return one mapblock at most. But make sure: Look whether the one we requested is in there List<MapBlockData> mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks(minX, minY, maxX, maxY); if (mapBlocks != null) { foreach (MapBlockData block in mapBlocks) { if (block.X == minX && block.Y == minY) { // found it => add it to response response.Add(block); break; } } } if (response.Count == 0) { // response still empty => couldn't find the map-tile the user clicked on => tell the client MapBlockData block = new MapBlockData(); block.X = (ushort)minX; block.Y = (ushort)minY; block.Access = 254; // == not there response.Add(block); } remoteClient.SendMapBlock(response, 0); } else { // normal mapblock request. Use the provided values GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); } }
private void OnMapNameRequest(IClientAPI remoteClient, string mapName) { if (mapName.Length < 3) { remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); return; } // try to fetch from GridServer List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(UUID.Zero, mapName, 20); if (regionInfos == null) { m_log.Warn("[MAPSEARCHMODULE]: RequestNamedRegions returned null. Old gridserver?"); // service wasn't available; maybe still an old GridServer. Try the old API, though it will return only one region regionInfos = new List<GridRegion>(); GridRegion info = m_scene.GridService.GetRegionByName(UUID.Zero, mapName); if (info != null) regionInfos.Add(info); } List<MapBlockData> blocks = new List<MapBlockData>(); MapBlockData data; if (regionInfos.Count > 0) { foreach (GridRegion info in regionInfos) { data = new MapBlockData(); data.Agents = 0; data.Access = info.Access; data.MapImageID = info.TerrainImage; data.Name = info.RegionName; data.RegionFlags = 0; data.WaterHeight = 0; // not used data.X = (ushort)(info.RegionLocX / Constants.RegionSize); data.Y = (ushort)(info.RegionLocY / Constants.RegionSize); blocks.Add(data); } } // final block, closing the search result data = new MapBlockData(); data.Agents = 0; data.Access = 255; data.MapImageID = UUID.Zero; data.Name = mapName; data.RegionFlags = 0; data.WaterHeight = 0; // not used data.X = 0; data.Y = 0; blocks.Add(data); remoteClient.SendMapBlock(blocks, 2); }
private void OnMapNameRequest(IClientAPI remoteClient, string mapName) { if (mapName.Length < 3) { remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); return; } // try to fetch from GridServer List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); if (regionInfos == null) { m_log.Warn("[MAPSEARCHMODULE]: RequestNamedRegions returned null. Old gridserver?"); // service wasn't available; maybe still an old GridServer. Try the old API, though it will return only one region regionInfos = new List<GridRegion>(); GridRegion info = m_scene.GridService.GetRegionByName(m_scene.RegionInfo.ScopeID, mapName); if (info != null) regionInfos.Add(info); } else if (regionInfos.Count == 0 && mapName.StartsWith("http://")) remoteClient.SendAlertMessage("Hyperlink could not be established."); m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); List<MapBlockData> blocks = new List<MapBlockData>(); MapBlockData data; if (regionInfos.Count > 0) { foreach (GridRegion info in regionInfos) { data = new MapBlockData(); data.Agents = 0; data.Access = info.Access; data.MapImageId = UUID.Zero; // could use info.TerrainImage but it seems to break viewer2 data.Name = info.RegionName; data.RegionFlags = 0; // TODO not used? data.WaterHeight = 0; // not used data.X = (ushort)(info.RegionLocX / Constants.RegionSize); data.Y = (ushort)(info.RegionLocY / Constants.RegionSize); blocks.Add(data); } } // final block, closing the search result data = new MapBlockData(); data.Agents = 0; data.Access = 255; data.MapImageId = UUID.Zero; data.Name = ""; // mapName; data.RegionFlags = 0; data.WaterHeight = 0; // not used data.X = 0; data.Y = 0; blocks.Add(data); // not sure what the flags do here, but seems to be necessary // to set to "2" for viewer 2 remoteClient.SendMapBlock(blocks, 2); }
protected MapBlockData TerrainBlockFromGridRegion(GridRegion r) { MapBlockData block = new MapBlockData(); if (r == null) { block.Access = (byte)SimAccess.Down; block.MapImageID = UUID.Zero; return block; } block.Access = r.Access; block.MapImageID = r.TerrainMapImage; block.Name = r.RegionName; block.X = (ushort)(r.RegionLocX / Constants.RegionSize); block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); return block; }
/// <summary> /// Try to teleport an agent to a new region. /// </summary> /// <param name="remoteClient"></param> /// <param name="RegionHandle"></param> /// <param name="position"></param> /// <param name="lookAt"></param> /// <param name="flags"></param> public virtual void RequestTeleportToLocation(ScenePresence avatar, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) { if (!avatar.Scene.Permissions.CanTeleport(avatar.UUID)) return; bool destRegionUp = true; IEventQueue eq = avatar.Scene.RequestModuleInterface<IEventQueue>(); // Reset animations; the viewer does that in teleports. avatar.Animator.ResetAnimations(); if (regionHandle == m_regionInfo.RegionHandle) { m_log.DebugFormat( "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation {0} within {1}", position, m_regionInfo.RegionName); // Teleport within the same region if (IsOutsideRegion(avatar.Scene, position) || position.Z < 0) { Vector3 emergencyPos = new Vector3(128, 128, 128); m_log.WarnFormat( "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", position, avatar.Name, avatar.UUID, emergencyPos); position = emergencyPos; } // TODO: Get proper AVG Height float localAVHeight = 1.56f; float posZLimit = 22; // TODO: Check other Scene HeightField if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <=(int)Constants.RegionSize) { posZLimit = (float) avatar.Scene.Heightmap[(int) position.X, (int) position.Y]; } float newPosZ = posZLimit + localAVHeight; if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) { position.Z = newPosZ; } // Only send this if the event queue is null if (eq == null) avatar.ControllingClient.SendTeleportLocationStart(); avatar.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); avatar.Teleport(position); } else { uint x = 0, y = 0; Utils.LongToUInts(regionHandle, out x, out y); GridRegion reg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); if (reg != null) { m_log.DebugFormat( "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation to {0} in {1}", position, reg.RegionName); if (eq == null) avatar.ControllingClient.SendTeleportLocationStart(); // Let's do DNS resolution only once in this process, please! // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, // it's actually doing a lot of work. IPEndPoint endPoint = reg.ExternalEndPoint; if (endPoint.Address == null) { // Couldn't resolve the name. Can't TP, because the viewer wants IP addresses. destRegionUp = false; } if (destRegionUp) { uint newRegionX = (uint)(reg.RegionHandle >> 40); uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); uint oldRegionX = (uint)(m_regionInfo.RegionHandle >> 40); uint oldRegionY = (((uint)(m_regionInfo.RegionHandle)) >> 8); // Fixing a bug where teleporting while sitting results in the avatar ending up removed from // both regions if (avatar.ParentID != (uint)0) avatar.StandUp(); if (!avatar.ValidateAttachments()) { avatar.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); return; } // the avatar.Close below will clear the child region list. We need this below for (possibly) // closing the child agents, so save it here (we need a copy as it is Clear()-ed). //List<ulong> childRegions = new List<ulong>(avatar.GetKnownRegionList()); // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport // failure at this point (unlike a border crossing failure). So perhaps this can never fail // once we reach here... //avatar.Scene.RemoveCapsHandler(avatar.UUID); string capsPath = String.Empty; AgentCircuitData agentCircuit = avatar.ControllingClient.RequestClientInfo(); agentCircuit.BaseFolder = UUID.Zero; agentCircuit.InventoryFolder = UUID.Zero; agentCircuit.startpos = position; agentCircuit.child = true; if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY)) { // brand new agent, let's create a new caps seed agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } string reason = String.Empty; // Let's create an agent there if one doesn't exist yet. //if (!m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agentCircuit)) if (!m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, agentCircuit, teleportFlags, out reason)) { avatar.ControllingClient.SendTeleportFailed(String.Format("Destination is not accepting teleports: {0}", reason)); return; } // OK, it got this agent. Let's close some child agents avatar.CloseChildAgents(newRegionX, newRegionY); if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY)) { #region IP Translation for NAT IClientIPEndpoint ipepClient; if (avatar.ClientView.TryGet(out ipepClient)) { capsPath = "http://" + NetworkUtil.GetHostFor(ipepClient.EndPoint, reg.ExternalHostName) + ":" + reg.HttpPort + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); } else { capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); } #endregion if (eq != null) { #region IP Translation for NAT // Uses ipepClient above if (avatar.ClientView.TryGet(out ipepClient)) { endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); } #endregion eq.EnableSimulator(reg.RegionHandle, endPoint, avatar.UUID); // ES makes the client send a UseCircuitCode message to the destination, // which triggers a bunch of things there. // So let's wait Thread.Sleep(2000); eq.EstablishAgentCommunication(avatar.UUID, endPoint, capsPath); } else { avatar.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint); } } else { agentCircuit.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, reg.RegionHandle); capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort + "/CAPS/" + agentCircuit.CapsPath + "0000/"; } // Expect avatar crossing is a heavy-duty function at the destination. // That is where MakeRoot is called, which fetches appearance and inventory. // Plus triggers OnMakeRoot, which spawns a series of asynchronous updates. //m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId, // position, false); //{ // avatar.ControllingClient.SendTeleportFailed("Problem with destination."); // // We should close that agent we just created over at destination... // List<ulong> lst = new List<ulong>(); // lst.Add(reg.RegionHandle); // SendCloseChildAgentAsync(avatar.UUID, lst); // return; //} SetInTransit(avatar.UUID); // Let's send a full update of the agent. This is a synchronous call. AgentData agent = new AgentData(); avatar.CopyTo(agent); agent.Position = position; agent.CallbackURI = "http://" + m_regionInfo.ExternalHostName + ":" + m_regionInfo.HttpPort + "/agent/" + avatar.UUID.ToString() + "/" + avatar.Scene.RegionInfo.RegionHandle.ToString() + "/release/"; m_interregionCommsOut.SendChildAgentUpdate(reg.RegionHandle, agent); m_log.DebugFormat( "[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, avatar.UUID); if (eq != null) { eq.TeleportFinishEvent(reg.RegionHandle, 13, endPoint, 0, teleportFlags, capsPath, avatar.UUID); } else { avatar.ControllingClient.SendRegionTeleport(reg.RegionHandle, 13, endPoint, 4, teleportFlags, capsPath); } // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation // that the client contacted the destination before we send the attachments and close things here. if (!WaitForCallback(avatar.UUID)) { // Client never contacted destination. Let's restore everything back avatar.ControllingClient.SendTeleportFailed("Problems connecting to destination."); ResetFromTransit(avatar.UUID); // Yikes! We should just have a ref to scene here. avatar.Scene.InformClientOfNeighbours(avatar); // Finally, kill the agent we just created at the destination. m_interregionCommsOut.SendCloseAgent(reg.RegionHandle, avatar.UUID); return; } // Can't go back from here if (KiPrimitive != null) { KiPrimitive(avatar.LocalId); } avatar.MakeChildAgent(); // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it avatar.CrossAttachmentsIntoNewRegion(reg.RegionHandle, true); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY)) { Thread.Sleep(5000); avatar.Close(); CloseConnection(avatar.UUID); } else // now we have a child agent in this region. avatar.Reset(); // if (teleport success) // seems to be always success here // the user may change their profile information in other region, // so the userinfo in UserProfileCache is not reliable any more, delete it if (avatar.Scene.NeedSceneCacheClear(avatar.UUID)) { m_commsProvider.UserProfileCacheService.RemoveUser(avatar.UUID); m_log.DebugFormat( "[SCENE COMMUNICATION SERVICE]: User {0} is going to another region, profile cache removed", avatar.UUID); } } else { avatar.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); } } else { // TP to a place that doesn't exist (anymore) // Inform the viewer about that avatar.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); // and set the map-tile to '(Offline)' uint regX, regY; Utils.LongToUInts(regionHandle, out regX, out regY); MapBlockData block = new MapBlockData(); block.X = (ushort)(regX / Constants.RegionSize); block.Y = (ushort)(regY / Constants.RegionSize); block.Access = 254; // == not there List<MapBlockData> blocks = new List<MapBlockData>(); blocks.Add(block); avatar.ControllingClient.SendMapBlock(blocks, 0); } } }
/// <summary> /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates /// </summary> /// <param name="minX"></param> /// <param name="minY"></param> /// <param name="maxX"></param> /// <param name="maxY"></param> public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { if ((flag & 0x10000) != 0) // user clicked on the map a tile that isn't visible { List<MapBlockData> response = new List<MapBlockData>(); // this should return one mapblock at most. // (diva note: why?? in that case we should GetRegionByPosition) // But make sure: Look whether the one we requested is in there List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, minX * (int)Constants.RegionSize, maxX * (int)Constants.RegionSize, minY * (int)Constants.RegionSize, maxY * (int)Constants.RegionSize); if (regions != null) { foreach (GridRegion r in regions) { if ((r.RegionLocX == minX * (int)Constants.RegionSize) && (r.RegionLocY == minY * (int)Constants.RegionSize)) { // found it => add it to response MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r); response.Add(block); break; } } } if (response.Count == 0) { // response still empty => couldn't find the map-tile the user clicked on => tell the client MapBlockData block = new MapBlockData(); block.X = (ushort)minX; block.Y = (ushort)minY; block.Access = 254; // == not there response.Add(block); } remoteClient.SendMapBlock(response, 0); } else { // normal mapblock request. Use the provided values GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); } }
// Fill a passed MapBlockData from a GridRegion public MapBlockData MapBlockFromGridRegion(GridRegion r, uint flag) { MapBlockData block = new MapBlockData(); block.Access = r.Access; switch (flag & 0xffff) { case 0: block.MapImageId = r.TerrainImage; break; case 2: block.MapImageId = r.ParcelImage; break; default: block.MapImageId = UUID.Zero; break; } block.Name = r.RegionName; block.X = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocX); block.Y = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocY); block.SizeX = (ushort) r.RegionSizeX; block.SizeY = (ushort) r.RegionSizeY; return block; }
protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r) { block.Access = r.Access; block.MapImageId = r.TerrainImage; block.Name = r.RegionName; block.X = (ushort)(r.RegionLocX / Constants.RegionSize); block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); }
public List<MapBlockData> Map2BlockFromGridRegion(GridRegion r, uint flag) { List<MapBlockData> blocks = new List<MapBlockData>(); MapBlockData block = new MapBlockData(); if (r == null) { block.Access = (byte)SimAccess.Down; block.MapImageId = UUID.Zero; blocks.Add(block); } else { block.Access = r.Access; switch (flag & 0xffff) { case 0: block.MapImageId = r.TerrainImage; break; case 2: block.MapImageId = r.ParcelImage; break; default: block.MapImageId = UUID.Zero; break; } block.Name = r.RegionName; block.X = (ushort)(r.RegionLocX / Constants.RegionSize); block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); block.SizeX = (ushort)r.RegionSizeX; block.SizeY = (ushort)r.RegionSizeY; blocks.Add(block); } return blocks; }
public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) { if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) return; IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); // Reset animations; the viewer does that in teleports. sp.Animator.ResetAnimations(); try { if (regionHandle == sp.Scene.RegionInfo.RegionHandle) { m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation {0} within {1}", position, sp.Scene.RegionInfo.RegionName); // Teleport within the same region if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) { Vector3 emergencyPos = new Vector3(128, 128, 128); m_log.WarnFormat( "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", position, sp.Name, sp.UUID, emergencyPos); position = emergencyPos; } // TODO: Get proper AVG Height float localAVHeight = 1.56f; float posZLimit = 22; // TODO: Check other Scene HeightField if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) { posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; } float newPosZ = posZLimit + localAVHeight; if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) { position.Z = newPosZ; } sp.ControllingClient.SendTeleportStart(teleportFlags); sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); sp.Teleport(position); foreach (SceneObjectGroup grp in sp.GetAttachments()) { if (grp.IsDeleted) sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); } } else // Another region possibly in another simulator { uint x = 0, y = 0; Utils.LongToUInts(regionHandle, out x, out y); GridRegion reg = m_aScene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); if (reg != null) { GridRegion finalDestination = GetFinalDestination(reg); if (finalDestination == null) { m_log.WarnFormat("[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport agent."); sp.ControllingClient.SendTeleportFailed("Problem at destination"); return; } uint curX = 0, curY = 0; Utils.LongToUInts(sp.Scene.RegionInfo.RegionHandle, out curX, out curY); int curCellX = (int)(curX / Constants.RegionSize); int curCellY = (int)(curY / Constants.RegionSize); int destCellX = (int)(finalDestination.RegionLocX / Constants.RegionSize); int destCellY = (int)(finalDestination.RegionLocY / Constants.RegionSize); // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); // // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", // destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); // Check that these are not the same coordinates if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX && finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY) { // Can't do. Viewer crashes sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again."); return; } if (Math.Abs(curCellX - destCellX) > MaxTransferDistance || Math.Abs(curCellY - destCellY) > MaxTransferDistance) { sp.ControllingClient.SendTeleportFailed( string.Format( "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", finalDestination.RegionName, destCellX, destCellY, sp.Scene.RegionInfo.RegionName, curCellX, curCellY, MaxTransferDistance)); return; } // // This is it // DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags, eq); // // // } else { // TP to a place that doesn't exist (anymore) // Inform the viewer about that sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); // and set the map-tile to '(Offline)' uint regX, regY; Utils.LongToUInts(regionHandle, out regX, out regY); MapBlockData block = new MapBlockData(); block.X = (ushort)(regX / Constants.RegionSize); block.Y = (ushort)(regY / Constants.RegionSize); block.Access = 254; // == not there List<MapBlockData> blocks = new List<MapBlockData>(); blocks.Add(block); sp.ControllingClient.SendMapBlock(blocks, 0); } } } catch (Exception e) { m_log.WarnFormat("[ENTITY TRANSFER MODULE]: Exception on teleport: {0} {1}", e.Message, e.StackTrace); sp.ControllingClient.SendTeleportFailed("Internal error"); } }
/// <summary> /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates /// </summary> /// <param name="minX"></param> /// <param name="minY"></param> /// <param name="maxX"></param> /// <param name="maxY"></param> public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible { List<MapBlockData> response = new List<MapBlockData>(); // this should return one mapblock at most. It is triggered by a click // on an unloaded square. // But make sure: Look whether the one we requested is in there List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, (int)Util.RegionToWorldLoc((uint)minX), (int)Util.RegionToWorldLoc((uint)maxX), (int)Util.RegionToWorldLoc((uint)minY), (int)Util.RegionToWorldLoc((uint)maxY) ); m_log.DebugFormat("[WORLD MAP MODULE] RequestMapBlocks min=<{0},{1}>, max=<{2},{3}>, flag={4}, cntFound={5}", minX, minY, maxX, maxY, flag.ToString("X"), regions.Count); if (regions != null) { foreach (GridRegion r in regions) { if (r.RegionLocX == Util.RegionToWorldLoc((uint)minX) && r.RegionLocY == Util.RegionToWorldLoc((uint)minY) ) { // found it => add it to response // Version 2 viewers can handle the larger regions if ((flag & 2) == 2) response.AddRange(Map2BlockFromGridRegion(r, flag)); else response.Add(MapBlockFromGridRegion(r, flag)); break; } } } if (response.Count == 0) { // response still empty => couldn't find the map-tile the user clicked on => tell the client MapBlockData block = new MapBlockData(); block.X = (ushort)minX; block.Y = (ushort)minY; block.Access = (byte)SimAccess.Down; // means 'simulator is offline' // block.Access = (byte)SimAccess.NonExistent; response.Add(block); } // The lower 16 bits are an unsigned int16 remoteClient.SendMapBlock(response, flag & 0xffff); } else { // normal mapblock request. Use the provided values GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); } }