public RegionCombinerLargeLandChannel(RegionData regData, ILandChannel rootRegionLandChannel,
                                       List<RegionData> regionConnections)
 {
     RegData = regData;
     RootRegionLandChannel = rootRegionLandChannel;
     RegionConnections = regionConnections;
 }
 /// <summary>
 /// TODO:
 /// </summary>
 /// <param name="rdata"></param>
 public void UnCombineRegion(RegionData rdata)
 {
     lock (m_regions)
     {
         if (m_regions.ContainsKey(rdata.RegionId))
         {
             // uncombine root region and virtual regions
         }
         else
         {
             foreach (RegionConnections r in m_regions.Values)
             {
                 foreach (RegionData rd in r.ConnectedRegions)
                 {
                     if (rd.RegionId == rdata.RegionId)
                     {
                         // uncombine virtual region
                     }
                 }
             }
         }
     }
 }
        /// <summary>
        /// Locates a the Client of a particular region in an Array of RegionData based on offset
        /// </summary>
        /// <param name="offset"></param>
        /// <param name="uUID"></param>
        /// <param name="rdata"></param>
        /// <returns>IClientAPI or null</returns>
        private IClientAPI LocateUsersChildAgentIClientAPI(Vector2 offset, UUID uUID, RegionData[] rdata)
        {
            IClientAPI returnclient = null;
            foreach (RegionData r in rdata)
            {
                if (r.Offset.X == offset.X && r.Offset.Y == offset.Y)
                {
                    return r.RegionScene.SceneGraph.GetControllingClient(uUID);
                }
            }

            return returnclient;
        }
        private void DoWorkForRootRegion(RegionConnections regionConnections, Scene scene)
        {
            RegionData rdata = new RegionData();
            rdata.Offset = Vector3.Zero;
            rdata.RegionId = scene.RegionInfo.originRegionID;
            rdata.RegionScene = scene;
            // save it's land channel
            regionConnections.RegionLandChannel = scene.LandChannel;

            // Substitue our landchannel
            RegionCombinerLargeLandChannel lnd = new RegionCombinerLargeLandChannel(rdata, scene.LandChannel,
                                                            regionConnections.ConnectedRegions);
            scene.LandChannel = lnd;
            // Forward the permissions modules of each of the connected regions to the root region
            lock (m_regions)
            {
                foreach (RegionData r in regionConnections.ConnectedRegions)
                {
                    ForwardPermissionRequests(regionConnections, r.RegionScene);
                }
            }
            // Create the root region's Client Event Forwarder
            regionConnections.ClientEventForwarder = new RegionCombinerClientEventForwarder(regionConnections);

            // Sets up the CoarseLocationUpdate forwarder for this root region
            scene.EventManager.OnNewPresence += SetCourseLocationDelegate;

            // Adds this root region to a dictionary of regions that are connectable
            m_regions.Add(scene.RegionInfo.originRegionID, regionConnections);
        }
        private bool DoWorkForOneRegionOverPlusXPlusY(RegionConnections conn, RegionConnections regionConnections, Scene scene)
        {
            Vector3 offset = Vector3.Zero;
            offset.X = (((regionConnections.X * (int)Constants.RegionSize)) -
                        ((conn.X * (int)Constants.RegionSize)));
            offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) -
                        ((conn.Y * (int)Constants.RegionSize)));

            Vector3 extents = Vector3.Zero;
            extents.Y = regionConnections.YEnd + conn.YEnd;
            extents.X = regionConnections.XEnd + conn.XEnd;
            conn.UpdateExtents(extents);

            scene.BordersLocked = true;
            conn.RegionScene.BordersLocked = true;

            RegionData ConnectedRegion = new RegionData();
            ConnectedRegion.Offset = offset;
            ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
            ConnectedRegion.RegionScene = scene;

            conn.ConnectedRegions.Add(ConnectedRegion);

            m_log.DebugFormat("Scene: {0} to the NorthEast of Scene{1} Offset: {2}. Extents:{3}",
                             conn.RegionScene.RegionInfo.RegionName,
                             regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);

            conn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
            scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, Vector3.Zero);
            lock (conn.RegionScene.NorthBorders)
            {
                if (conn.RegionScene.NorthBorders.Count == 1)// &&  2)
                {
                    //compound border
                    // already locked above
                    conn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;

                    lock (conn.RegionScene.EastBorders)
                        conn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;
                    lock (conn.RegionScene.WestBorders)
                        conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
                }
            }

            lock (scene.SouthBorders)
            {
                scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - conn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
                scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
                scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
            }

            lock (conn.RegionScene.EastBorders)
            {
                if (conn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2)
                {

                    conn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize;
                    lock (conn.RegionScene.NorthBorders)
                        conn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize;
                    lock (conn.RegionScene.SouthBorders)
                        conn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize;


                }
            }

            lock (scene.WestBorders)
            {
                scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - conn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West
                scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
                scene.WestBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
            }

            /*
                                    else
                                    {
                                        conn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;
                                        conn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;
                                        conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
                                        scene.SouthBorders[0].BorderLine.Z += (int)Constants.RegionSize; //auto teleport south
                                    }
            */


            // Reset Terrain..  since terrain normally loads first.
            //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
            scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
            //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
            scene.BordersLocked = false;
            conn.RegionScene.BordersLocked = false;

            if (conn.ClientEventForwarder != null)
                conn.ClientEventForwarder.AddSceneToEventForwarding(scene);

            return true;

            //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents);

        }
        private bool DoWorkForOneRegionOverPlusXY(RegionConnections conn, RegionConnections regionConnections, Scene scene)
        {
            Vector3 offset = Vector3.Zero;
            offset.X = (((regionConnections.X * (int)Constants.RegionSize)) -
                        ((conn.X * (int)Constants.RegionSize)));
            offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) -
                        ((conn.Y * (int)Constants.RegionSize)));

            Vector3 extents = Vector3.Zero;
            extents.Y = conn.YEnd;
            extents.X = conn.XEnd + regionConnections.XEnd;

            conn.UpdateExtents(extents);

            m_log.DebugFormat("Scene: {0} to the west of Scene{1} Offset: {2}. Extents:{3}",
                              conn.RegionScene.RegionInfo.RegionName,
                              regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);

            scene.BordersLocked = true;
            conn.RegionScene.BordersLocked = true;

            RegionData ConnectedRegion = new RegionData();
            ConnectedRegion.Offset = offset;
            ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
            ConnectedRegion.RegionScene = scene;
            conn.ConnectedRegions.Add(ConnectedRegion);

            // Inform root region Physics about the extents of this region
            conn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);

            // Inform Child region that it needs to forward it's terrain to the root region
            scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, Vector3.Zero);

            // Extend the borders as appropriate
            lock (conn.RegionScene.EastBorders)
                conn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize;

            lock (conn.RegionScene.NorthBorders)
                conn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize;

            lock (conn.RegionScene.SouthBorders)
                conn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize;

            lock (scene.WestBorders)
            {


                scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - conn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West

                // Trigger auto teleport to root region
                scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX;
                scene.WestBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY;
            }

            // Reset Terrain..  since terrain loads before we get here, we need to load 
            // it again so it loads in the root region

            scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());

            // Unlock borders
            conn.RegionScene.BordersLocked = false;
            scene.BordersLocked = false;

            // Create a client event forwarder and add this region's events to the root region.
            if (conn.ClientEventForwarder != null)
                conn.ClientEventForwarder.AddSceneToEventForwarding(scene);

            return true;
        }
        /// <summary>
        /// Locates a the Client of a particular region in an Array of RegionData based on offset
        /// </summary>
        /// <param name="offset"></param>
        /// <param name="uUID"></param>
        /// <param name="rdata"></param>
        /// <returns>IClientAPI or null</returns>
        private IClientAPI LocateUsersChildAgentIClientAPI(Vector2 offset, UUID uUID, RegionData[] rdata)
        {
            foreach (RegionData r in rdata)
            {
                if (r.Offset.X == offset.X && r.Offset.Y == offset.Y)
                {
                    if(r.RegionScene.GetScenePresence(uUID) != null)
                        return r.RegionScene.GetScenePresence(uUID).ControllingClient;
                }
            }

            return null;
        }
        private void DoWorkForRootRegion(RegionConnections regionConnections, Scene scene)
        {
            RegionData rdata = new RegionData();
            rdata.Offset = Vector3.Zero;
            rdata.RegionId = scene.RegionInfo.RegionID;
            rdata.RegionScene = scene;
            // save it's land channel
            regionConnections.RegionLandChannel = scene.RequestModuleInterface<IParcelManagementModule>();

            // Substitue our landchannel
            RegionCombinerLargeLandChannel lnd = new RegionCombinerLargeLandChannel(rdata, scene.RequestModuleInterface<IParcelManagementModule>(),
                                                            regionConnections.ConnectedRegions);
            scene.RegisterModuleInterface<IParcelManagementModule>(lnd);
            // Forward the permissions modules of each of the connected regions to the root region
            lock (m_regions)
            {
                foreach (RegionData r in regionConnections.ConnectedRegions)
                {
                    ForwardPermissionRequests(regionConnections, r.RegionScene);
                }
            }
            // Create the root region's Client Event Forwarder
            regionConnections.ClientEventForwarder = new RegionCombinerClientEventForwarder(regionConnections);

            // Sets up the CoarseLocationUpdate forwarder for this root region
            scene.EventManager.OnNewPresence += SetCourseLocationDelegate;

            scene.EventManager.OnNewClient += EventManager_OnNewClient;
            scene.EventManager.OnClosingClient += OnClosingClient;

            // Adds this root region to a dictionary of regions that are connectable
            m_regions.Add(scene.RegionInfo.RegionID, regionConnections);
            ITerrainChannel terrainHeightmap = scene.RequestModuleInterface<ITerrainChannel>();
            landTerrainChannel.AddRegion(rdata, terrainHeightmap);
        }
        private bool DoWorkForOneRegionOverPlusXPlusY(RegionConnections conn, RegionConnections regionConnections, Scene scene)
        {
            Vector3 offset = Vector3.Zero;
            offset.X = (((regionConnections.X)) -
                        ((conn.X)));
            offset.Y = (((regionConnections.Y)) -
                        ((conn.Y)));

            Vector3 extents = Vector3.Zero;
            extents.Y = regionConnections.YEnd + conn.YEnd;
            extents.X = regionConnections.XEnd + conn.XEnd;
            conn.UpdateExtents(extents);

            RegionData ConnectedRegion = new RegionData();
            ConnectedRegion.Offset = offset;
            ConnectedRegion.RegionId = scene.RegionInfo.RegionID;
            ConnectedRegion.RegionScene = scene;

            conn.ConnectedRegions.Add(ConnectedRegion);

            m_log.DebugFormat("Scene: {0} to the NorthEast of Scene{1} Offset: {2}. Extents:{3}",
                             conn.RegionScene.RegionInfo.RegionName,
                             regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);

            conn.RegionScene.SceneGraph.PhysicsScene.Combine(null, Vector3.Zero, extents);
            scene.SceneGraph.PhysicsScene.Combine(conn.RegionScene.SceneGraph.PhysicsScene, offset, Vector3.Zero);
            
            // Reset Terrain..  since terrain normally loads first.
            //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
            ITerrainChannel terrainHeightmap = scene.RequestModuleInterface<ITerrainChannel>();
            scene.SceneGraph.PhysicsScene.SetTerrain(terrainHeightmap.GetFloatsSerialised(scene), terrainHeightmap.GetDoubles(scene));
            //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
            
            if (conn.ClientEventForwarder != null)
                conn.ClientEventForwarder.AddSceneToEventForwarding(scene);

            landTerrainChannel.AddRegion(ConnectedRegion, terrainHeightmap);

            return true;

            //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents);

        }
        private bool DoWorkForOneRegionOverPlusXY(RegionConnections conn, RegionConnections regionConnections, Scene scene)
        {
            Vector3 offset = Vector3.Zero;
            offset.X = (((regionConnections.X)) -
                        ((conn.X)));
            offset.Y = (((regionConnections.Y)) -
                        ((conn.Y)));

            Vector3 extents = Vector3.Zero;
            extents.Y = conn.YEnd;
            extents.X = conn.XEnd + regionConnections.XEnd;

            conn.UpdateExtents(extents);

            m_log.DebugFormat("Scene: {0} to the west of Scene{1} Offset: {2}. Extents:{3}",
                              conn.RegionScene.RegionInfo.RegionName,
                              regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);

            RegionData ConnectedRegion = new RegionData();
            ConnectedRegion.Offset = offset;
            ConnectedRegion.RegionId = scene.RegionInfo.RegionID;
            ConnectedRegion.RegionScene = scene;
            conn.ConnectedRegions.Add(ConnectedRegion);

            // Inform root region Physics about the extents of this region
            conn.RegionScene.SceneGraph.PhysicsScene.Combine(null, Vector3.Zero, extents);

            // Inform Child region that it needs to forward it's terrain to the root region
            scene.SceneGraph.PhysicsScene.Combine(conn.RegionScene.SceneGraph.PhysicsScene, offset, Vector3.Zero);

            // Reset Terrain..  since terrain loads before we get here, we need to load 
            // it again so it loads in the root region
            ITerrainChannel terrainHeightmap = scene.RequestModuleInterface<ITerrainChannel>();
            scene.SceneGraph.PhysicsScene.SetTerrain(terrainHeightmap.GetFloatsSerialised(scene), terrainHeightmap.GetDoubles(scene));

            // Create a client event forwarder and add this region's events to the root region.
            if (conn.ClientEventForwarder != null)
                conn.ClientEventForwarder.AddSceneToEventForwarding(scene);

            landTerrainChannel.AddRegion(ConnectedRegion, terrainHeightmap);
            return true;
        }
        private bool DoWorkForOneRegionOverPlusXY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
        {
            // Offset (in meters) from the base of this region to the base of the root region.
            Vector3 offset = Vector3.Zero;
            offset.X = newConn.PosX - rootConn.PosX;
            offset.Y = newConn.PosY - rootConn.PosY;

            // The new total size of the region (in meters)
            // We just extend the X and Y dimensions so the extent might temporarily include areas without regions.
            Vector3 extents = Vector3.Zero;
            extents.X = Math.Max(rootConn.XEnd, offset.X + newConn.RegionScene.RegionInfo.RegionSizeX);
            extents.Y = Math.Max(rootConn.YEnd, offset.Y + newConn.RegionScene.RegionInfo.RegionSizeY);

            rootConn.UpdateExtents(extents);

            m_log.DebugFormat(
                "[REGION COMBINER MODULE]: Root region {0} is to the west of region {1}, Offset: {2}, Extents: {3}",
                rootConn.RegionScene.RegionInfo.RegionName,
                newConn.RegionScene.RegionInfo.RegionName, offset, extents);

            RegionData ConnectedRegion = new RegionData();
            ConnectedRegion.Offset = offset;
            ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
            ConnectedRegion.RegionScene = scene;
            rootConn.ConnectedRegions.Add(ConnectedRegion);

            // Inform root region Physics about the extents of this region
            rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);

            // Inform Child region that it needs to forward it's terrain to the root region
            scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);

            // Reset Terrain..  since terrain loads before we get here, we need to load 
            // it again so it loads in the root region
            scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());

            // Create a client event forwarder and add this region's events to the root region.
            if (rootConn.ClientEventForwarder != null)
                rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);

            return true;
        }
        private bool DoWorkForOneRegionOverPlusXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
        {
            Vector3 offset = Vector3.Zero;
            offset.X = newConn.PosX - rootConn.PosX;
            offset.Y = newConn.PosY - rootConn.PosY;

            Vector3 extents = Vector3.Zero;

            // We do not want to inflate the extents for regions strictly to the NE of the root region, since this
            // would double count regions strictly to the north and east that have already been added.
//            extents.Y = regionConnections.YEnd + conn.YEnd;
//            extents.X = regionConnections.XEnd + conn.XEnd;
//            conn.UpdateExtents(extents);

            extents.Y = rootConn.YEnd;
            extents.X = rootConn.XEnd;

            scene.BordersLocked = true;
            rootConn.RegionScene.BordersLocked = true;

            RegionData ConnectedRegion = new RegionData();
            ConnectedRegion.Offset = offset;
            ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
            ConnectedRegion.RegionScene = scene;

            rootConn.ConnectedRegions.Add(ConnectedRegion);

            m_log.DebugFormat(
                "[REGION COMBINER MODULE]: Region {0} is to the southwest of Scene {1}, Offset: {2}, Extents: {3}",
                rootConn.RegionScene.RegionInfo.RegionName,
                newConn.RegionScene.RegionInfo.RegionName, offset, extents);

            rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
            scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);

            lock (rootConn.RegionScene.NorthBorders)
            {
                if (rootConn.RegionScene.NorthBorders.Count == 1)// &&  2)
                {
                    //compound border
                    // already locked above
                    rootConn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;

                    lock (rootConn.RegionScene.EastBorders)
                        rootConn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;

                    lock (rootConn.RegionScene.WestBorders)
                        rootConn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
                }
            }

            lock (scene.SouthBorders)
            {
                scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - rootConn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
                scene.SouthBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
                scene.SouthBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
            }

            lock (rootConn.RegionScene.EastBorders)
            {
                if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2)
                {

                    rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize;

                    lock (rootConn.RegionScene.NorthBorders)
                        rootConn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize;

                    lock (rootConn.RegionScene.SouthBorders)
                        rootConn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize;
                }
            }

            lock (scene.WestBorders)
            {
                scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - rootConn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West
                scene.WestBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
                scene.WestBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
            }

            /*
                                    else
                                    {
                                        conn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;
                                        conn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;
                                        conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
                                        scene.SouthBorders[0].BorderLine.Z += (int)Constants.RegionSize; //auto teleport south
                                    }
            */


            // Reset Terrain..  since terrain normally loads first.
            //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
            scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
            //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
            scene.BordersLocked = false;
            rootConn.RegionScene.BordersLocked = false;

            if (rootConn.ClientEventForwarder != null)
                rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);

            return true;

            //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents);
        }
        private bool DoWorkForOneRegionOverXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
        {
            Vector3 offset = Vector3.Zero;
            offset.X = newConn.PosX - rootConn.PosX;
            offset.Y = newConn.PosY - rootConn.PosY;

            Vector3 extents = Vector3.Zero;
            extents.Y = newConn.YEnd + rootConn.YEnd;
            extents.X = rootConn.XEnd;
            rootConn.UpdateExtents(extents);

            scene.BordersLocked = true;
            rootConn.RegionScene.BordersLocked = true;

            RegionData ConnectedRegion = new RegionData();
            ConnectedRegion.Offset = offset;
            ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
            ConnectedRegion.RegionScene = scene;
            rootConn.ConnectedRegions.Add(ConnectedRegion);

            m_log.DebugFormat(
                "[REGION COMBINER MODULE]: Root region {0} is to the south of region {1}, Offset: {2}, Extents: {3}",
                rootConn.RegionScene.RegionInfo.RegionName,
                newConn.RegionScene.RegionInfo.RegionName, offset, extents);

            rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
            scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);

            lock (rootConn.RegionScene.NorthBorders)
                rootConn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;

            lock (rootConn.RegionScene.EastBorders)
                rootConn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;

            lock (rootConn.RegionScene.WestBorders)
                rootConn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;

            lock (scene.SouthBorders)
            {
                scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - rootConn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
                scene.SouthBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
                scene.SouthBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
            }

            // Reset Terrain..  since terrain normally loads first.
            //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
            scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
            //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());

            scene.BordersLocked = false;
            rootConn.RegionScene.BordersLocked = false;

            if (rootConn.ClientEventForwarder != null)
                rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);

            return true;
        }
        private void RegionLoadedDoWork(Scene scene)
        {
            lock (m_startingScenes)
                m_startingScenes.Add(scene.RegionInfo.originRegionID, scene);

            // Give each region a standard set of non-infinite borders
            Border northBorder = new Border();
            northBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, (int)Constants.RegionSize);  //<---
            northBorder.CrossDirection = Cardinals.N;
            scene.NorthBorders[0] = northBorder;

            Border southBorder = new Border();
            southBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, 0);    //--->
            southBorder.CrossDirection = Cardinals.S;
            scene.SouthBorders[0] = southBorder;

            Border eastBorder = new Border();
            eastBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, (int)Constants.RegionSize);   //<---
            eastBorder.CrossDirection = Cardinals.E;
            scene.EastBorders[0] = eastBorder;

            Border westBorder = new Border();
            westBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, 0);     //--->
            westBorder.CrossDirection = Cardinals.W;
            scene.WestBorders[0] = westBorder;

            RegionConnections regionConnections = new RegionConnections();
            regionConnections.ConnectedRegions = new List<RegionData>();
            regionConnections.RegionScene = scene;
            regionConnections.RegionLandChannel = scene.LandChannel;
            regionConnections.RegionId = scene.RegionInfo.originRegionID;
            regionConnections.X = scene.RegionInfo.RegionLocX;
            regionConnections.Y = scene.RegionInfo.RegionLocY;
            regionConnections.XExtend = (int)Constants.RegionSize;
            regionConnections.YExtend = (int)Constants.RegionSize;


            if (m_nRegions == 0)
            {
                // this is root region
                regionConnections.XExtend *= m_numberCombinedRegionsX;
                regionConnections.YExtend *= m_numberCombinedRegionsY;

                m_rootScene = scene;
                m_rootConnection = regionConnections;

                // save it's land channel
                regionConnections.RegionLandChannel = scene.LandChannel;

                scene.RootScene = null;
                scene.RegionInfo.CombinedRegionHandle = 0;

                Vector3 extents;
                extents.X = regionConnections.XExtend;
                extents.Y = regionConnections.YExtend;
                extents.Z = 0;

                scene.RegionInfo.RegionSizeX = (uint)extents.X;
                scene.RegionInfo.RegionSizeY = (uint)extents.Y;

//                scene.PhysicsScene.Combine(null, Vector3.Zero, extents);

                lock (scene.SouthBorders)
                    scene.SouthBorders[0].BorderLine.Y = regionConnections.XExtend;

                lock (scene.WestBorders)
                    scene.WestBorders[0].BorderLine.Y = regionConnections.YExtend;

                lock (scene.EastBorders)
                {
                    scene.EastBorders[0].BorderLine.Z = regionConnections.XExtend;
                    scene.EastBorders[0].BorderLine.Y = regionConnections.YExtend;
                }

                lock (scene.NorthBorders)
                {
                    scene.NorthBorders[0].BorderLine.Z = regionConnections.YExtend;
                    scene.NorthBorders[0].BorderLine.Y = regionConnections.XExtend;
                }

                // Substitue our landchannel

                RegionData rdata = new RegionData();
                rdata.Offset = Vector3.Zero;
                rdata.RegionId = scene.RegionInfo.originRegionID;
                rdata.RegionScene = scene;

                RegionCombinerLargeLandChannel lnd = new RegionCombinerLargeLandChannel(rdata, scene.LandChannel,
                                                                regionConnections.ConnectedRegions);

                scene.LandChannel = lnd;
                // Forward the permissions modules of each of the connected regions to the root region
                // Create the root region's Client Event Forwarder
                regionConnections.ClientEventForwarder = new RegionCombinerClientEventForwarder(regionConnections);

                // Sets up the CoarseLocationUpdate forwarder for this root region
                scene.EventManager.OnNewPresence += SetCourseLocationDelegate;

                // Adds this root region to a dictionary of regions that are connectable
                m_regions.Add(scene.RegionInfo.originRegionID, regionConnections);
               
            }

            else if (m_rootScene != null)
            {
                scene.RootScene = m_rootScene;
                scene.RegionInfo.CombinedRegionHandle = m_rootScene.RegionInfo.RegionHandle;

                Vector3 offset = Vector3.Zero;
                offset.X = ((int)regionConnections.X - (int)m_rootConnection.X) * Constants.RegionSize;
                offset.Y = ((int)regionConnections.Y - (int)m_rootConnection.Y) * Constants.RegionSize;

                RegionData ConnectedRegion = new RegionData();
                ConnectedRegion.Offset = offset;
                ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
                ConnectedRegion.RegionScene = scene;
                m_rootConnection.ConnectedRegions.Add(ConnectedRegion);

                scene.Physics_Enabled = false;
                scene.Scripts_Enabled = false;


                m_rootScene.PhysicsScene.CombineTerrain(scene.Heightmap.GetFloatsSerialised(),offset);

                scene.EventManager.OnNewPresence += SetCourseLocationDelegate;
                // Create a client event forwarder and add this region's events to the root region.
                
                if (m_rootConnection.ClientEventForwarder != null)
                    m_rootConnection.ClientEventForwarder.AddSceneToEventForwarding(scene);
            }

            m_nRegions++;

            if (m_nRegions == m_nRegionsToLoad)
            {
                // final work
                lock (m_regions)
                {
                    foreach (RegionData r in regionConnections.ConnectedRegions)
                    {
                        ForwardPermissionRequests(regionConnections, r.RegionScene);
                    }
                }
            }

            AdjustLargeRegionBounds();
            return;

        }