diff --git a/OpenSim/Data/MSSQL/MSSQLLegacyRegionData.cs b/OpenSim/Data/MSSQL/MSSQLLegacyRegionData.cs index d6cb91f27f..ffb053f7ac 100644 --- a/OpenSim/Data/MSSQL/MSSQLLegacyRegionData.cs +++ b/OpenSim/Data/MSSQL/MSSQLLegacyRegionData.cs @@ -1564,5 +1564,12 @@ VALUES #endregion #endregion + + #region REGION SYNC + public List LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY) + { + return null; + } + #endregion REGION SYNC } } diff --git a/OpenSim/Data/MySQL/MySQLLegacyRegionData.cs b/OpenSim/Data/MySQL/MySQLLegacyRegionData.cs index bfeae12385..97b77f3c8e 100644 --- a/OpenSim/Data/MySQL/MySQLLegacyRegionData.cs +++ b/OpenSim/Data/MySQL/MySQLLegacyRegionData.cs @@ -523,6 +523,148 @@ namespace OpenSim.Data.MySQL return new List(objects.Values); } + #region REGION SYNC + public List LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY) + { + const int ROWS_PER_QUERY = 5000; + + Dictionary prims = new Dictionary(ROWS_PER_QUERY); + Dictionary objects = new Dictionary(); + int count = 0; + + #region Prim Loading + + lock (m_dbLock) + { + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + { + dbcon.Open(); + + using (MySqlCommand cmd = dbcon.CreateCommand()) + { + //cmd.CommandText = + // "SELECT * FROM prims LEFT JOIN primshapes ON prims.UUID = primshapes.UUID WHERE RegionUUID = ?RegionUUID"; + cmd.CommandText = "SELECT * FROM prims LEFT JOIN primshapes ON prims.UUID = primshapes.UUID WHERE RegionUUID = ?RegionUUID " + + "and GroupPositionX>=?lowerX " + + "and GroupPositionX<=?upperX and GroupPositionY>=?lowerY and GroupPositionY<=?upperY "; + cmd.Parameters.AddWithValue("RegionUUID", regionID.ToString()); + cmd.Parameters.AddWithValue("lowerX", lowerX); + cmd.Parameters.AddWithValue("lowerY", lowerY); + cmd.Parameters.AddWithValue("upperX", upperX); + cmd.Parameters.AddWithValue("upperY", upperY); + + using (IDataReader reader = ExecuteReader(cmd)) + { + while (reader.Read()) + { + SceneObjectPart prim = BuildPrim(reader); + if (reader["Shape"] is DBNull) + prim.Shape = PrimitiveBaseShape.Default; + else + prim.Shape = BuildShape(reader); + + UUID parentID = DBGuid.FromDB(reader["SceneGroupID"].ToString()); + if (parentID != prim.UUID) + prim.ParentUUID = parentID; + + prims[prim.UUID] = prim; + + ++count; + if (count % ROWS_PER_QUERY == 0) + m_log.Debug("[REGION DB]: Loaded " + count + " prims..."); + } + } + } + } + } + + #endregion Prim Loading + + #region SceneObjectGroup Creation + + // Create all of the SOGs from the root prims first + foreach (SceneObjectPart prim in prims.Values) + { + if (prim.ParentUUID == UUID.Zero) + objects[prim.UUID] = new SceneObjectGroup(prim); + } + + // Add all of the children objects to the SOGs + foreach (SceneObjectPart prim in prims.Values) + { + SceneObjectGroup sog; + if (prim.UUID != prim.ParentUUID) + { + if (objects.TryGetValue(prim.ParentUUID, out sog)) + { + int originalLinkNum = prim.LinkNum; + + sog.AddPart(prim); + + // SceneObjectGroup.AddPart() tries to be smart and automatically set the LinkNum. + // We override that here + if (originalLinkNum != 0) + prim.LinkNum = originalLinkNum; + } + else + { + m_log.WarnFormat( + "[REGION DB]: Database contains an orphan child prim {0} {1} in region {2} pointing to missing parent {3}. This prim will not be loaded.", + prim.Name, prim.UUID, regionID, prim.ParentUUID); + } + } + } + + #endregion SceneObjectGroup Creation + + m_log.DebugFormat("[REGION DB]: Loaded {0} objects using {1} prims", objects.Count, prims.Count); + + #region Prim Inventory Loading + + // Instead of attempting to LoadItems on every prim, + // most of which probably have no items... get a + // list from DB of all prims which have items and + // LoadItems only on those + List primsWithInventory = new List(); + lock (m_dbLock) + { + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + { + dbcon.Open(); + + using (MySqlCommand itemCmd = dbcon.CreateCommand()) + { + itemCmd.CommandText = "SELECT DISTINCT primID FROM primitems"; + using (IDataReader itemReader = ExecuteReader(itemCmd)) + { + while (itemReader.Read()) + { + if (!(itemReader["primID"] is DBNull)) + { + UUID primID = DBGuid.FromDB(itemReader["primID"].ToString()); + if (prims.ContainsKey(primID)) + primsWithInventory.Add(prims[primID]); + } + } + } + } + } + } + + foreach (SceneObjectPart prim in primsWithInventory) + { + LoadItems(prim); + } + + #endregion Prim Inventory Loading + + m_log.DebugFormat("[REGION DB]: Loaded inventory from {0} objects", primsWithInventory.Count); + + return new List(objects.Values); + } + #endregion REGION SYNC + + /// /// Load in a prim's persisted inventory. /// diff --git a/OpenSim/Data/Null/NullDataStore.cs b/OpenSim/Data/Null/NullDataStore.cs index 3ba44bb54b..44284f0ac3 100644 --- a/OpenSim/Data/Null/NullDataStore.cs +++ b/OpenSim/Data/Null/NullDataStore.cs @@ -108,5 +108,12 @@ namespace OpenSim.Data.Null public void Shutdown() { } + + #region REGION SYNC + public List LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY) + { + return null; + } + #endregion REGION SYNC } } diff --git a/OpenSim/Data/SQLite/SQLiteRegionData.cs b/OpenSim/Data/SQLite/SQLiteRegionData.cs index 81d0ac4f6e..218d7f9c34 100644 --- a/OpenSim/Data/SQLite/SQLiteRegionData.cs +++ b/OpenSim/Data/SQLite/SQLiteRegionData.cs @@ -2332,5 +2332,11 @@ namespace OpenSim.Data.SQLite } } + #region REGION SYNC + public List LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY) + { + return null; + } + #endregion REGION SYNC } } diff --git a/OpenSim/Data/SQLiteLegacy/SQLiteRegionData.cs b/OpenSim/Data/SQLiteLegacy/SQLiteRegionData.cs index eb78037bb1..8a8f2c6623 100644 --- a/OpenSim/Data/SQLiteLegacy/SQLiteRegionData.cs +++ b/OpenSim/Data/SQLiteLegacy/SQLiteRegionData.cs @@ -2260,5 +2260,11 @@ namespace OpenSim.Data.SQLiteLegacy } } + #region REGION SYNC + public List LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY) + { + return null; + } + #endregion REGION SYNC } } diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 4a043c05bd..00fb10412e 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -359,8 +359,59 @@ namespace OpenSim "kill uuid ", "Kill an object by UUID", KillUUID); + //REGION SYNC + //Add one more command handler for "sync start", to pass simulator-wise information to one valide Scene. + //A trick to enable Script Engine to run scripts in several adjacent regions (all objects and their scripts + //exisited in the valid region, but all regions have their Scene data structure up and hold the RegionInfo. + //More details, see ScriptEngineToSceneConnector.cs. + m_console.Commands.AddCommand("region", false, "sync start", + "sync start", + "start synchronization with the authoratative Scene", SyncStart); + //End REGION SYNC } + #region REGION SYNC + protected void SyncStart(string module, string[] cmdparams) + { + m_log.Debug("OpenSim: receives sync start command, do something"); + + //string validLocalScene = m_config. + IConfig regionSyncConfig = m_config.Source.Configs["RegionSyncModule"]; + + if (regionSyncConfig == null || regionSyncConfig.GetString("Enabled", "").ToLower() != "true") + { + m_log.Warn("[OpenSim] Not in sync mode. Ignore cmmand."); + return; + } + + if (regionSyncConfig.GetString("Mode", "").ToLower() == "server") + { + m_log.Warn("[OpenSim] In server mode. Should not initiate sync start. Ignore command."); + return; + } + + if (regionSyncConfig.GetString("Mode", "").ToLower() == "script_engine") + { + //if this is a remote script engine, proceed with following actions + string validSceneName = regionSyncConfig.GetString("ValidScriptEngineScene", ""); + + if (!validSceneName.Equals("")) + { + Scene validScene; + m_sceneManager.TryGetScene(validSceneName, out validScene); + + List localScenes = m_sceneManager.Scenes; + //First, let the valid scene's SEToSceneConnector be aware of all local scenes. + //The SEToSceneConnector will also pass a reference to all other scenes, so that they can + //call the appropriate IsBorderCrossing(). + validScene.EventManager.TriggerPopulateLocalSceneList(localScenes); //TO BE FINISHED + //validScene.EventManager.TriggerPopulateLocalSceneList(localScenes, cmdparams); + } + } + } + #endregion REGION SYNC + + public override void ShutdownSpecific() { if (m_shutdownCommandsFile != String.Empty) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs index a75e3b184c..77b35896a6 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs @@ -71,6 +71,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private string m_regionName; private System.Timers.Timer m_statsTimer = new System.Timers.Timer(30000); + + //KittyL: added to identify different actors + private ActorType m_actorType = ActorType.ClientManager; + + // The queue of incoming messages which need handling + //private Queue m_inQ = new Queue(); #endregion // Constructor @@ -704,6 +710,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private void DoInitialSync() { m_scene.DeleteAllSceneObjects(); + //KittyL: added to distinguish different actors + Send(new RegionSyncMessage(RegionSyncMessage.MsgType.ActorType, m_actorType.ToString())); + Send(new RegionSyncMessage(RegionSyncMessage.MsgType.RegionName, m_scene.RegionInfo.RegionName)); m_log.WarnFormat("Sending region name: \"{0}\"", m_scene.RegionInfo.RegionName); Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetTerrain)); diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncMessage.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncMessage.cs index 342df3f041..da24ba6eba 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncMessage.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncMessage.cs @@ -5,18 +5,39 @@ using log4net; namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { + #region ActorType Enum + public enum ActorType + { + Null, + ClientManager, + ScriptEngine + } + #endregion + + #region ActorStatus Enum + public enum ActorStatus + { + Null, + Idle, + Sync + } + #endregion + /// /// A message for synchonization message between scenes /// public class RegionSyncMessage { + //KittyL: added to help identify different actors + + #region MsgType Enum public enum MsgType { Null, //ConnectSyncClient, //DisconnectSyncClient, - // CM -> SIM + // CM -> SIM(Scene) ActorConnect, AgentAdd, AgentUpdate, @@ -45,7 +66,38 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule EchoRequest, EchoResponse, RegionName, - RegionStatus + RegionStatus, + //Added by KittyL + // Actor -> Scene + ActorType, //to register the type (e.g. Client Manager or Script Engine) with Scene when sync channel is initialized + SetObjectProperty, + ActorStop, + ResetScene, + OnRezScript, + OnScriptReset, + OnUpdateScript, + QuarkSubscription, + // Scene -> Script Engine + NewObjectWithScript, + SceneLocation, + //For load balancing purpose (among script engines) + //Temorarily put here, for easier first round of implemention. + //Script engine --> Scene + ActorStatus, //if the actor is busying syncing with a Scene, or is just idle. Status: {sync, idle} + LoadBalanceRequest, + LoadMigrationListenerInitiated, + //Scene --> Script engine + LoadMigrationNotice, + LoadBalanceResponse, + LoadBalanceRejection, + //Overloaded script engine overloaded -> idle script engine + //MigratingQuarks, + MigrationSpace, + ScriptStateSyncStart, + ScriptStateSyncPerObject, + ScriptStateSyncEnd, + //Idle script engine overloaded -> overloaded script engine + ScriptStateSyncRequest, } #endregion diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServer.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServer.cs index eac886d8e9..07ca8af9a8 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServer.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServer.cs @@ -9,6 +9,7 @@ using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenMetaverse; using log4net; +using OpenSim.Region.Framework.Scenes.Serialization; namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { @@ -192,5 +193,16 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { m_ClientBalancer.BalanceLoad(); } + //KittyL: + public void BroadcastToCM(RegionSyncMessage.MsgType msgType, SceneObjectGroup sog) + { + string sogxml = SceneObjectSerializer.ToXml2Format(sog); + + //m_log.Debug("SOG " + sog.UUID); + + RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.NewObject, sogxml); + Broadcast(rsm); + } + } } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs index 4a34de14dc..c1a5889836 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs @@ -47,21 +47,72 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { public class RegionSyncServerModule : IRegionModule, IRegionSyncServerModule, ICommandableModule { + private static int DefaultPort = 13000; + #region IRegionModule Members public void Initialise(Scene scene, IConfigSource config) { m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + // If no syncConfig, do not start up server mode IConfig syncConfig = config.Configs["RegionSyncModule"]; - if (syncConfig == null || syncConfig.GetString("Mode", "server").ToLower() != "server") + if (syncConfig == null) { + scene.RegionSyncEnabled = false; m_active = false; - m_log.Warn("[REGION SYNC SERVER MODULE] Not in server mode. Shutting down."); + m_log.Warn("[REGION SYNC SERVER MODULE] No RegionSyncModule config section found. Shutting down."); return; } - m_serveraddr = syncConfig.GetString("ServerIPAddress", "127.0.0.1"); - m_serverport = syncConfig.GetInt("ServerPort", 13000); + + // If syncConfig does not indicate "enabled", do not start up server mode + bool enabled = syncConfig.GetBoolean("Enabled", true); + if(!enabled) + { + scene.RegionSyncEnabled = false; + m_active = false; + m_log.Warn("[REGION SYNC SERVER MODULE] RegionSyncModule is not enabled. Shutting down."); + return; + } + + // If syncConfig does not indicate "server", do not start up server mode + string mode = syncConfig.GetString("Mode", "server").ToLower(); + if(mode != "server") + { + scene.RegionSyncEnabled = false; + m_active = false; + m_log.WarnFormat("[REGION SYNC SERVER MODULE] RegionSyncModule is in {0} mode. Shutting down.", mode); + return; + } + + // Enable region sync in server mode on the scene and module + scene.RegionSyncEnabled = true; + scene.RegionSyncMode = mode; + m_active = true; + + // Init the sync statistics log file + string syncstats = "syncstats" + "_" + scene.RegionInfo.RegionName + ".txt"; + m_statsWriter = File.AppendText(syncstats); + + //Get sync server info for Client Manager actors + string serverAddr = scene.RegionInfo.RegionName + "_ServerIPAddress"; + m_serveraddr = syncConfig.GetString(serverAddr, "127.0.0.1"); + string serverPort = scene.RegionInfo.RegionName + "_ServerPort"; + m_serverport = syncConfig.GetInt(serverPort, DefaultPort); + // Client manager load balancing m_maxClientsPerManager = syncConfig.GetInt("MaxClientsPerManager", 100); + DefaultPort++; + + //Get sync server info for Script Engine actors + string seServerAddr = scene.RegionInfo.RegionName + "_SceneToSESyncServerIP"; + m_seSyncServeraddr = syncConfig.GetString(seServerAddr, "127.0.0.1"); + string seServerPort = scene.RegionInfo.RegionName + "_SceneToSESyncServerPort"; + m_seSyncServerport = syncConfig.GetInt(seServerPort, DefaultPort); + DefaultPort++; + + //Get quark information + QuarkInfo.SizeX = syncConfig.GetInt("QuarkSizeX", (int)Constants.RegionSize); + QuarkInfo.SizeY = syncConfig.GetInt("QuarkSizeY", (int)Constants.RegionSize); + m_scene = scene; m_scene.RegisterModuleInterface(this); @@ -90,6 +141,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_scene.SceneGraph.OnObjectDuplicate += new ObjectDuplicateDelegate(SceneGraph_OnObjectDuplicate); //m_scene.SceneGraph.OnObjectRemove += new ObjectDeleteDelegate(SceneGraph_OnObjectRemove); //m_scene.StatsReporter.OnSendStatsResult += new SimStatsReporter.SendStatResult(StatsReporter_OnSendStatsResult); + m_scene.EventManager.OnOarFileLoaded += new EventManager.OarFileLoaded(EventManager_OnOarFileLoaded); m_log.Warn("[REGION SYNC SERVER MODULE] Starting RegionSyncServer"); // Start the server and listen for RegionSyncClients @@ -97,17 +149,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_server.Start(); m_statsTimer.Elapsed += new System.Timers.ElapsedEventHandler(StatsTimerElapsed); m_statsTimer.Start(); + + m_log.Warn("[REGION SYNC SERVER MODULE] Starting SceneToScriptEngineSyncServer"); + //Start the sync server for script engines + m_sceneToSESyncServer = new SceneToScriptEngineSyncServer(m_scene, m_seSyncServeraddr, m_seSyncServerport); + m_sceneToSESyncServer.Start(); //m_log.Warn("[REGION SYNC SERVER MODULE] Post-Initialised"); } private void StatsTimerElapsed(object source, System.Timers.ElapsedEventArgs e) { if (Synced) - { - TextWriter tw = File.AppendText("syncstats.txt"); - m_server.ReportStats(tw); - tw.Close(); - } + m_server.ReportStats(m_statsWriter); } void IRegionModule.Close() @@ -124,6 +177,15 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { get { return false; } } + + + //KittyL added + //Later, should make quarkIDs the argument to the function call + //public void SendResetScene() + //{ + // m_server.Broadcast(new RegionSyncMessage(RegionSyncMessage.MsgType.ResetScene, "reset")); + //} + #endregion #region ICommandableModule Members @@ -142,6 +204,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private Dictionary m_presenceUpdates = new Dictionary(); private System.Timers.Timer m_statsTimer = new System.Timers.Timer(1000); + //private TextWriter m_statsWriter = File.AppendText("syncstats.txt"); + private TextWriter m_statsWriter; public void QueuePartForUpdate(SceneObjectPart part) { @@ -198,8 +262,19 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { if (!sog.IsDeleted) { + /* string sogxml = SceneObjectSerializer.ToXml2Format(sog); + + m_log.Debug("[REGION SYNC SERVER MODULE]: to update object " + sog.UUID + ", localID: "+sog.LocalId + + ", with color " + sog.RootPart.Shape.Textures.DefaultTexture.RGBA.A + + "," + sog.RootPart.Shape.Textures.DefaultTexture.RGBA.B + "," + sog.RootPart.Shape.Textures.DefaultTexture.RGBA.G + + "," + sog.RootPart.Shape.Textures.DefaultTexture.RGBA.R); + m_server.Broadcast(new RegionSyncMessage(RegionSyncMessage.MsgType.UpdatedObject, sogxml)); + * */ + //KittyL: modified to broadcast to different types of actors + m_server.BroadcastToCM(RegionSyncMessage.MsgType.UpdatedObject, sog); + m_sceneToSESyncServer.SendToSE(RegionSyncMessage.MsgType.UpdatedObject, sog); } } foreach (ScenePresence presence in presenceUpdates) @@ -211,11 +286,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule OSDMap data = new OSDMap(7); data["id"] = OSD.FromUUID(presence.UUID); // Do not include offset for appearance height. That will be handled by RegionSyncClient before sending to viewers - if (presence.AbsolutePosition.IsFinite()) + if(presence.AbsolutePosition.IsFinite()) data["pos"] = OSD.FromVector3(presence.AbsolutePosition); else data["pos"] = OSD.FromVector3(Vector3.Zero); - if (presence.Velocity.IsFinite()) + if(presence.Velocity.IsFinite()) data["vel"] = OSD.FromVector3(presence.Velocity); else data["vel"] = OSD.FromVector3(Vector3.Zero); @@ -225,6 +300,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule data["anim"] = OSD.FromString(presence.Animator.CurrentMovementAnimation); RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.UpdatedAvatar, OSDParser.SerializeJsonString(data)); m_server.EnqueuePresenceUpdate(presence.UUID, rsm.ToBytes()); + } } catch (Exception e) @@ -268,15 +344,35 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_appearanceTimers[agentID] = appearanceSetter; } - public void DeleteObject(ulong regionHandle, uint localID) + public void DeleteObject(ulong regionHandle, uint localID, SceneObjectPart part) { if (!Active || !Synced) return; + + //First, tell client managers to remove the SceneObjectPart OSDMap data = new OSDMap(2); data["regionHandle"] = OSD.FromULong(regionHandle); data["localID"] = OSD.FromUInteger(localID); RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.RemovedObject, OSDParser.SerializeJsonString(data)); + //m_server.BroadcastToCM(rsm); m_server.Broadcast(rsm); + + //KittyL: Second, tell script engine to remove the object, identified by UUID + //UUID objID = m_scene.GetSceneObjectPart(localID).ParentGroup.UUID; + //SceneObjectPart part = m_scene.GetSceneObjectPart(localID); + if (part != null) + { + data = new OSDMap(1); + + data["UUID"] = OSD.FromUUID(part.UUID); + rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.RemovedObject, OSDParser.SerializeJsonString(data)); + + //when an object is deleted, this function (DeleteObject) could be triggered more than once. So we check + //if the object part is already removed is the scene (part==null) + m_log.Debug("Inform script engine about the deleted object"); + m_sceneToSESyncServer.SendToSE(rsm, part.ParentGroup); + } + } public bool Active @@ -284,17 +380,26 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule get { return m_active; } } - // Check if the sync server module is connected to any clients + // Check if the sync server module is connected to any clients (KittyL: edited for testing if connected to any actors) public bool Synced { get { if (m_server == null || !m_server.Synced) + //if((m_server == null || !m_server.Synced) && (m_sceneToSESyncServer==null || !m_sceneToSESyncServer.Synced)) return false; return true; } } + public void SendLoadWorldMap(ITerrainChannel heightMap) + { + RegionSyncMessage msg = new RegionSyncMessage(RegionSyncMessage.MsgType.Terrain, m_scene.Heightmap.SaveToXmlString()); + m_server.Broadcast(msg); + //KittyL: added for SE + m_sceneToSESyncServer.SendToAllConnectedSE(msg); + } + #region cruft #if false @@ -350,6 +455,16 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private ILog m_log; //private int m_moveCounter = 0; private RegionSyncServer m_server = null; + + //Sync-server for script engines + private string m_seSyncServeraddr; + private int m_seSyncServerport; + private SceneToScriptEngineSyncServer m_sceneToSESyncServer = null; + + //quark related information + //private int QuarkInfo.SizeX; + //private int QuarkInfo.SizeY; + #endregion #region Event Handlers @@ -357,11 +472,27 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { if (!Synced) return; + +// m_log.Debug("[RegionSyncServerModule]: SceneGraph_OnObjectCreate() called"); + if (entity is SceneObjectGroup) { + /* string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)entity); + + SceneObjectGroup sog = (SceneObjectGroup)entity; + m_log.Debug("SOG " + sog.UUID); + RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.NewObject, sogxml); - m_server.Broadcast(rsm); + //KittyL: edited to support both Client Manager and Script Engine actors + //m_server.Broadcast(rsm); + m_server.BroadcastToCM(rsm); + * */ + SceneObjectGroup sog = (SceneObjectGroup)entity; + m_server.BroadcastToCM(RegionSyncMessage.MsgType.NewObject, sog); + + m_sceneToSESyncServer.SendToSE(RegionSyncMessage.MsgType.NewObject, sog); + } else { @@ -375,9 +506,13 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return; if (original is SceneObjectGroup && copy is SceneObjectGroup) { - string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)copy); - RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.NewObject, sogxml); - m_server.Broadcast(rsm); + + //string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)copy); + //RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.NewObject, sogxml); + //m_server.Broadcast(rsm); + SceneObjectGroup sog = (SceneObjectGroup)copy; + m_server.BroadcastToCM(RegionSyncMessage.MsgType.NewObject, sog); + m_sceneToSESyncServer.SendToSE(RegionSyncMessage.MsgType.NewObject, sog); } else { @@ -394,6 +529,20 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // No reason to send the entire object, just send the UUID to be deleted RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.RemovedObject, entity.UUID.ToString()); m_server.Broadcast(rsm); + + SceneObjectPart part = m_scene.GetSceneObjectPart(entity.UUID); + if (part != null) + { + OSDMap data = new OSDMap(1); + + data["UUID"] = OSD.FromUUID(part.UUID); + rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.RemovedObject, OSDParser.SerializeJsonString(data)); + + //when an object is deleted, this function (DeleteObject) could be triggered more than once. So we check + //if the object part is already removed is the scene (part==null) + m_log.Debug("Inform script engine about the deleted object"); + m_sceneToSESyncServer.SendToSE(rsm, part.ParentGroup); + } } else { @@ -532,6 +681,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_server.Broadcast(new RegionSyncMessage(RegionSyncMessage.MsgType.RemovedAvatar, OSDParser.SerializeJsonString(data))); } + private void EventManager_OnOarFileLoaded(Guid requestID, string errorMsg) + { + //we ignore the requestID and the errorMsg + SendLoadWorldMap(m_scene.Heightmap); + } + #endregion #region Console Command Interface @@ -609,6 +764,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.DebugFormat("[REGION SYNC SERVER MODULE] LocalChat({0},{1})", msg, channel); m_scene.EventManager.TriggerOnChatBroadcast(this, osm); } + } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 6be20d37ce..e32dbb3bfd 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -188,7 +188,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation { if (s.RegionInfo.RegionHandle == destination.RegionHandle) { - m_log.WarnFormat("[LOCAL SIMULATION CONNECTOR]: Found region {0} to send SendCreateChildAgent", destination.RegionName); + m_log.DebugFormat("[LOCAL SIMULATION CONNECTOR]: Found region {0} to send SendCreateChildAgent", destination.RegionName); return s.NewUserConnection(aCircuit, teleportFlags, out reason); } } diff --git a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs index fd43923cb3..27cb80a855 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs @@ -76,6 +76,10 @@ namespace OpenSim.Region.Framework.Interfaces ArrayList GetScriptErrors(UUID itemID); void ResumeScripts(); + #region REGION SYNC + void SuspendScripts(); + #endregion REGION SYNC + /// /// Stop all the scripts in this entity. /// diff --git a/OpenSim/Region/Framework/Interfaces/IRegionDataStore.cs b/OpenSim/Region/Framework/Interfaces/IRegionDataStore.cs index 3e8e19670c..71db5c0ee5 100644 --- a/OpenSim/Region/Framework/Interfaces/IRegionDataStore.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionDataStore.cs @@ -107,5 +107,9 @@ namespace OpenSim.Region.Framework.Interfaces void StoreRegionWindlightSettings(RegionLightShareData wl); void Shutdown(); + + #region REGION SYNC + List LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY); + #endregion REGION SYNC } } diff --git a/OpenSim/Region/Framework/Interfaces/IRegionSyncServerModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionSyncServerModule.cs index 9d6f240f2d..84f0969d40 100644 --- a/OpenSim/Region/Framework/Interfaces/IRegionSyncServerModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionSyncServerModule.cs @@ -41,8 +41,13 @@ namespace OpenSim.Region.Framework.Interfaces void QueuePartForUpdate(SceneObjectPart part); void QueuePresenceForTerseUpdate(ScenePresence presence); void SendUpdates(); - void DeleteObject(ulong regionHandle, uint localID); + //void DeleteObject(ulong regionHandle, uint localID); + void DeleteObject(ulong regionHandle, uint localID, SceneObjectPart part); void SendAppearance(UUID agentID, byte[] vp, Primitive.TextureEntry te); + //KittyL: added to support remote script engine actor + //void SendRezScript(SceneObjectGroup sog); + //void SendResetScene(); + void SendLoadWorldMap(ITerrainChannel heightMap); } } diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 9db2e4135b..8d1ef77f68 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -335,6 +335,7 @@ namespace OpenSim.Region.Framework.Scenes public delegate void RegionUp(GridRegion region); public event RegionUp OnRegionUp; + public class MoneyTransferArgs : EventArgs { public UUID sender; @@ -2013,5 +2014,86 @@ namespace OpenSim.Region.Framework.Scenes } } } + + //REGION SYNC + #region REGION SYNC RELATED EVENTS + + //OnScriptEngineSyncStop: triggered when user types "sync stop" on the script engine's console + public delegate void ScriptEngineSyncStop(); + public event ScriptEngineSyncStop OnScriptEngineSyncStop; + public void TriggerScriptEngineSyncStop() + { + ScriptEngineSyncStop handlerScriptEngineSyncStop = OnScriptEngineSyncStop; + if (handlerScriptEngineSyncStop != null) + { + foreach (ScriptEngineSyncStop d in handlerScriptEngineSyncStop.GetInvocationList()) + { + try + { + d(); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[EVENT MANAGER]: Delegate for TriggerScriptEngineSyncStop failed - continuing. {0} {1}", + e.Message, e.StackTrace); + } + } + } + } + + //OnUpdateTaskInventoryScriptAsset: triggered after Scene receives client's upload of updated script and stores it as asset + public delegate void UpdateScript(UUID clientID, UUID itemId, UUID primId, bool isScriptRunning, UUID newAssetID); + public event UpdateScript OnUpdateScript; + public void TriggerUpdateScript(UUID clientId, UUID itemId, UUID primId, bool isScriptRunning, UUID newAssetID) + { + UpdateScript handlerUpdateScript = OnUpdateScript; + if (handlerUpdateScript != null) + { + foreach (UpdateScript d in handlerUpdateScript.GetInvocationList()) + { + try + { + d(clientId, itemId, primId, isScriptRunning, newAssetID); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[EVENT MANAGER]: Delegate for TriggerUpdateScript failed - continuing. {0} {1}", + e.Message, e.StackTrace); + } + } + } + } + + //OnPopulateLocalSceneList: Triggered by OpenSim to the valid local scene, should only happen in script engine + public delegate void PopulateLocalSceneList(List localScenes); + public event PopulateLocalSceneList OnPopulateLocalSceneList; + public void TriggerPopulateLocalSceneList(List localScenes) + //public delegate void PopulateLocalSceneList(List localScenes, string[] cmdparams); + //public event PopulateLocalSceneList OnPopulateLocalSceneList; + //public void TriggerPopulateLocalSceneList(List localScenes, string[] cmdparams) + { + PopulateLocalSceneList handlerPopulateLocalSceneList = OnPopulateLocalSceneList; + if (handlerPopulateLocalSceneList != null) + { + foreach (PopulateLocalSceneList d in handlerPopulateLocalSceneList.GetInvocationList()) + { + try + { + d(localScenes); + //d(localScenes, cmdparams); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[EVENT MANAGER]: Delegate for TriggerPopulateLocalSceneList failed - continuing. {0} {1}", + e.Message, e.StackTrace); + } + } + } + } + #endregion + } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 6e73fe920f..c8af7c6a8d 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -149,6 +149,11 @@ namespace OpenSim.Region.Framework.Scenes return UUID.Zero; } + //////////////////////////////////////////////////////////////////////////////////////////////// + //REGION SYNC + //Scene does permission checking, asset creation and storing, then informs Script Engine to + //update the script. + //////////////////////////////////////////////////////////////////////////////////////////////// /// /// Capability originating call to update the asset of a script in a prim's (task's) inventory /// @@ -195,9 +200,13 @@ namespace OpenSim.Region.Framework.Scenes AssetBase asset = CreateAsset(item.Name, item.Description, (sbyte)AssetType.LSLText, data, remoteClient.AgentId); AssetService.Store(asset); - if (isScriptRunning) + //REGION SYNC: if RegionSyncEnabled, move script related operations to be after update inventory item + if (!RegionSyncEnabled) { - part.Inventory.RemoveScriptInstance(item.ItemID, false); + if (isScriptRunning) + { + part.Inventory.RemoveScriptInstance(item.ItemID, false); + } } // Update item with new asset @@ -207,23 +216,89 @@ namespace OpenSim.Region.Framework.Scenes part.GetProperties(remoteClient); - // Trigger rerunning of script (use TriggerRezScript event, see RezScript) + ////REGION SYNC + if (!RegionSyncEnabled) + { + //Original OpenSim code below + + // Trigger rerunning of script (use TriggerRezScript event, see RezScript) + ArrayList errors = new ArrayList(); + + if (isScriptRunning) + { + // Needs to determine which engine was running it and use that + // + part.Inventory.CreateScriptInstance(item.ItemID, 0, false, DefaultScriptEngine, 0); + errors = part.Inventory.GetScriptErrors(item.ItemID); + } + else + { + remoteClient.SendAgentAlertMessage("Script saved", false); + } + part.ParentGroup.ResumeScripts(); + return errors; + } + else + { + //Distributed Scene Graph is in place, trigger event OnUpdateScript to + //let SceneToSEConnector to contact remote script engine for script update + m_log.Debug("Scene.Inventory: to call EventManager.TriggerUpdateTaskInventoryScriptAsset, agentID: " + remoteClient.AgentId); + EventManager.TriggerUpdateScript(remoteClient.AgentId, itemId, primId, isScriptRunning, item.AssetID); + + //For now, we simple tell client that script saved while waiting for remote script engine to re-rez the script. + //Later will change the BaseHttpServer's code to return error list to client. + remoteClient.SendAgentAlertMessage("Script saved", false); + ArrayList errors = new ArrayList(); + return errors; + + } + } + + #region REGION SYNC + //////////////////////////////////////////////////////////////////////////////////////////////// + //REGION SYNC + //Scene does permission checking, asset creation and storing, then informs Script Engine to + //update the script. + //////////////////////////////////////////////////////////////////////////////////////////////// + //Only should be called when this is the cached Scene of script engine (e.g. from ScriptEngineToSceneConnector) + public ArrayList OnUpdateScript(UUID avatarID, UUID itemID, UUID primID, bool isScriptRunning, UUID newAssetID) + { ArrayList errors = new ArrayList(); + //This function is supposed to be executed only on a remote script engine, not an authorative Scene + if (!IsSyncedScriptEngine()) + { + m_log.Warn("This is not the script engine. Should not have received OnUpdateScript event."); + return errors; + } + SceneObjectPart part = GetSceneObjectPart(primID); + SceneObjectGroup group = part.ParentGroup; + if (isScriptRunning) + { + m_log.Debug("To RemoveScriptInstance"); + part.Inventory.RemoveScriptInstance(itemID, false); + } + + // Retrieve item + TaskInventoryItem item = group.GetInventoryItem(part.LocalId, itemID); + + // Update item with new asset + item.AssetID = newAssetID; + group.UpdateInventoryItem(item); + m_log.Debug("UpdateInventoryItem on object "+group.UUID); if (isScriptRunning) { // Needs to determine which engine was running it and use that - // - part.Inventory.CreateScriptInstance(item.ItemID, 0, false, DefaultScriptEngine, 0); - errors = part.Inventory.GetScriptErrors(item.ItemID); - } - else - { - remoteClient.SendAgentAlertMessage("Script saved", false); + m_log.Debug("To CreateScriptInstance"); + part.Inventory.CreateScriptInstance(itemID, 0, false, DefaultScriptEngine, 0); + errors = part.Inventory.GetScriptErrors(itemID); } + part.ParentGroup.ResumeScripts(); + return errors; } + #endregion /// /// CapsUpdateTaskInventoryScriptAsset(IClientAPI, UUID, UUID, bool, byte[]) @@ -235,6 +310,8 @@ namespace OpenSim.Region.Framework.Scenes if (TryGetScenePresence(avatarId, out avatar)) { + //REGION SYNC LOG + m_log.Debug("Scene.Inventory: Avatar " + avatarId + ", triggers UpdateTaskInventoryScriptAsset"); return CapsUpdateTaskInventoryScriptAsset( avatar.ControllingClient, itemId, primId, isScriptRunning, data); } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index cb89f5ed65..8ee8bfc88f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -322,6 +322,7 @@ namespace OpenSim.Region.Framework.Scenes protected IDialogModule m_dialogModule; protected IEntityTransferModule m_teleportModule; + #region REGION SYNC protected IRegionSyncServerModule m_regionSyncServerModule; protected IRegionSyncClientModule m_regionSyncClientModule; @@ -344,11 +345,152 @@ namespace OpenSim.Region.Framework.Scenes return (m_regionSyncClientModule != null && m_regionSyncClientModule.Active && m_regionSyncClientModule.Synced); } + //Return true if the sync server thread is active (Mode == server) and has some actors connected public bool IsSyncedServer() { return (m_regionSyncServerModule != null && m_regionSyncServerModule.Active && m_regionSyncServerModule.Synced); } + /////////////////////////////////////////////////////////////////////////////////////////////// + //KittyL: below variables and functions added to support additional actors, e.g. script engine + /////////////////////////////////////////////////////////////////////////////////////////////// + + //Return true if the sync server thread is active (Mode == server) + public bool IsAuthoritativeScene() + { + //if this is the authoratative scene, then m_regionSyncServerModule.Active == true (mode=server) + return (m_regionSyncServerModule != null && m_regionSyncServerModule.Active); + } + + private bool m_regionSyncEnabled = false; + public bool RegionSyncEnabled + { + get { return m_regionSyncEnabled; } + set { m_regionSyncEnabled = value; } + } + + private string m_regionSyncMode = ""; + public string RegionSyncMode + { + get { return m_regionSyncMode; } + set { m_regionSyncMode = value; } + } + + + protected IScriptEngineToSceneConnectorModule m_scriptEngineToSceneConnectorModule; + + + public IScriptEngineToSceneConnectorModule ScriptEngineToSceneConnectorModule + { + get { return m_scriptEngineToSceneConnectorModule; } + set { m_scriptEngineToSceneConnectorModule = value; } + } + + public bool IsSyncedScriptEngine() + { + return (m_scriptEngineToSceneConnectorModule != null && m_scriptEngineToSceneConnectorModule.Active && m_scriptEngineToSceneConnectorModule.Synced); + } + + public bool ToScheduleFullUpdate() + { + //Only Scene (SyncServer) or Client Manager (SyncClient) will schedule update to send to its client. Script Engine will not (its update should be sent to Scene). + return (IsSyncedClient() || IsSyncedServer() || (IsSyncedScriptEngine() && m_scriptEngineToSceneConnectorModule.DebugWithViewer)); + } + + + public bool ToRezScriptByRemoteScriptEngine() + { + //Only Auth. Scene should trigger scritp rez by remote script engine. + return IsSyncedServer(); + } + + + //This function should only be called by an actor who's local Scene is just a cache of the authorative Scene. + //If the object already exists, use the new copy to replace it. + //Return true if added, false if just updated + public bool AddOrUpdateObjectInLocalScene(SceneObjectGroup sog, bool debugWithViewer) + { + return m_sceneGraph.AddOrUpdateObjectInScene(sog, debugWithViewer); + + } + + //public delegate bool TestBorderCrossingOutsideScenes(Scene currentScene, Vector3 pos); + public delegate bool TestBorderCrossingOutsideScenes(uint locX, uint locY, Vector3 pos); + private TestBorderCrossingOutsideScenes m_isOutsideScenesFunc = null; + public TestBorderCrossingOutsideScenes IsOutsideScenes + { + get { return m_isOutsideScenesFunc; } + set { m_isOutsideScenesFunc = value; } + } + + /// + /// This is the given position goes outside of the current scene (if not a script engine executing this function), + /// or outside of all scenes hosted by the script engine. Parameters curLocX, curLocY, and offset uniquely identify + /// the position in the entire space. + /// + /// the X coordinate of the scene's left-bottom corner + /// the Y coordinate of the scene's left-bottom corner + /// the offset position to the scene's left-bottom corner + /// + public bool IsBorderCrossing(uint curLocX, uint curLocY, Vector3 offset) + { + Vector3 val = offset; + if (!RegionSyncEnabled || !(RegionSyncMode == "script_engine")) + { + //if we are not running Region Sync code, or if we are but this OpenSim instance is not the script engine, then + //proceed as original code + bool crossing = TestBorderCross(val - Vector3.UnitX, Cardinals.E) || TestBorderCross(val + Vector3.UnitX, Cardinals.W) + || TestBorderCross(val - Vector3.UnitY, Cardinals.N) || TestBorderCross(val + Vector3.UnitY, Cardinals.S); + return crossing; + } + else + { + //this is script engine + if (m_isOutsideScenesFunc == null) + { + m_log.Warn("Scene " + RegionInfo.RegionName + ": Function IsOutsideScenes not hooked up yet"); + return false; + } + + return m_isOutsideScenesFunc(curLocX, curLocY, val); + } + } + + public void LoadPrimsFromStorageInGivenSpace(string regionName, float minX, float minY, float maxX, float maxY) + { + m_log.Info("[SCENE]: Loading objects from datastore"); + + GridRegion regionInfo = GridService.GetRegionByName(UUID.Zero, regionName); + //TODO: need to load objects from the specified space + List PrimsFromDB = m_storageManager.DataStore.LoadObjectsInGivenSpace(regionInfo.RegionID, minX, minY, maxX, maxY); + + m_log.Info("[SCENE]: Loaded " + PrimsFromDB.Count + " objects from the datastore"); + + foreach (SceneObjectGroup group in PrimsFromDB) + { + if (group.RootPart == null) + { + m_log.ErrorFormat("[SCENE] Found a SceneObjectGroup with m_rootPart == null and {0} children", + group.Children == null ? 0 : group.Children.Count); + } + + AddRestoredSceneObject(group, true, true); + SceneObjectPart rootPart = group.GetChildPart(group.UUID); + rootPart.ObjectFlags &= ~(uint)PrimFlags.Scripted; + rootPart.TrimPermissions(); + group.CheckSculptAndLoad(); + //rootPart.DoPhysicsPropertyUpdate(UsePhysics, true); + } + m_log.Info("[SCENE]: Loaded " + PrimsFromDB.Count.ToString() + " SceneObject(s)"); + } + + //public void ToInformActorsLoadOar() + //{ + // m_regionSyncServerModule.SendResetScene(); + // } + + #endregion + protected ICapabilitiesModule m_capsModule; public ICapabilitiesModule CapsModule { @@ -1293,8 +1435,11 @@ namespace OpenSim.Region.Framework.Scenes m_dialogModule = RequestModuleInterface(); m_capsModule = RequestModuleInterface(); m_teleportModule = RequestModuleInterface(); + + //REGION SYNC RegionSyncServerModule = RequestModuleInterface(); RegionSyncClientModule = RequestModuleInterface(); + ScriptEngineToSceneConnectorModule = RequestModuleInterface(); // Shoving this in here for now, because we have the needed // interfaces at this point @@ -1900,6 +2045,11 @@ namespace OpenSim.Region.Framework.Scenes { m_log.Warn("[TERRAIN]: Scene.cs: LoadWorldMap() - Failed with exception " + e.ToString()); } + + //REGION SYNC + //Inform actors of the new terrain + if (IsSyncedServer()) + RegionSyncServerModule.SendLoadWorldMap(Heightmap); } /// @@ -3510,7 +3660,7 @@ namespace OpenSim.Region.Framework.Scenes // REGION SYNC if( IsSyncedServer() ) - RegionSyncServerModule.DeleteObject(m_regionHandle, localID); + RegionSyncServerModule.DeleteObject(m_regionHandle, localID, part); } #endregion diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 602b32f2eb..2506e9c1ad 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -352,14 +352,24 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.AttachToScene(m_parentScene); + //KittyL: edited to support script engine actor + //if (sendClientUpdates) + // sceneObject.ScheduleGroupForFullUpdate(); if (sendClientUpdates) + { sceneObject.ScheduleGroupForFullUpdate(); + } Entities.Add(sceneObject); m_numPrim += sceneObject.Children.Count; - if (attachToBackup) + //KittyL: edited to support script engine actor + //if (attachToBackup) + // sceneObject.AttachToBackup(); + if (attachToBackup && m_parentScene.IsAuthoritativeScene()) + { sceneObject.AttachToBackup(); + } if (OnObjectCreate != null) OnObjectCreate(sceneObject); @@ -607,7 +617,7 @@ namespace OpenSim.Region.Framework.Scenes { Dictionary newmap = new Dictionary(m_scenePresenceMap); List newlist = new List(m_scenePresenceArray); - + // Remove the presence reference from the dictionary if (newmap.ContainsKey(agentID)) { @@ -1828,6 +1838,62 @@ namespace OpenSim.Region.Framework.Scenes #endregion - + #region REGION SYNC + + protected internal bool IsObjectInScene(SceneObjectGroup sog) + { + if (Entities.ContainsKey(sog.UUID)) + return true; + else + { + return false; + } + } + + //Return false if the entity with the UUID is not a SceneObjectGroup, + //otherwise, return true. + protected internal bool AddOrUpdateObjectInScene(SceneObjectGroup updatedSog, bool debugWithViewer) + { + UUID sogID = updatedSog.UUID; + + if (Entities.ContainsKey(sogID)) + { + //update the object + EntityBase entity = Entities[sogID]; + if (entity is SceneObjectGroup) + { + SceneObjectGroup oldSog = (SceneObjectGroup)entity; + oldSog.UpdateObjectProperties(updatedSog); + + if (debugWithViewer) + { + //if we need to debug the script engine with a viewer attaching to it, + //we need to schedule updates to be sent to the viewer + oldSog.ScheduleGroupForFullUpdate(); + } + } + else + { + m_log.Warn("Entity with " + sogID + " is not of type SceneObjectGroup"); + //return false; + } + return false; + } + else + { + //Add a new object + //For now, we set sendClientUpdates to true, for debugging purpose -- so that we could log a viewer in to + //see if scripts are running properly + //Since this is a Script Engine's local Scene cache, do not backup to DB + AddSceneObject(updatedSog, false, debugWithViewer); + //AddSceneObject(updatedSog, false, false); + + return true; + } + + } + + #endregion + } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index 9a01a28b36..6c38d63fb9 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs @@ -429,5 +429,15 @@ namespace OpenSim.Region.Framework.Scenes part.Inventory.ResumeScripts(); } } + + #region REGION SYNC + public void SuspendScripts() + { + foreach (SceneObjectPart part in m_parts.Values) + { + part.Inventory.SuspendScripts(); + } + } + #endregion REGION SYNC } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 7ba20b496d..1476e98678 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -292,12 +292,16 @@ namespace OpenSim.Region.Framework.Scenes { Vector3 val = value; - if ((m_scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || m_scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) - || m_scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || m_scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) - && !IsAttachmentCheckFull()) + //REGION SYNC touched + + //if ((m_scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || m_scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) + // || m_scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || m_scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) + // && !IsAttachmentCheckFull()) + if (m_scene.IsBorderCrossing(LocX, LocY, val) && !IsAttachmentCheckFull()) { m_scene.CrossPrimGroupIntoNewRegion(val, this, true); } + //end REGION SYNC touched if (RootPart.GetStatusSandbox()) { if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) @@ -1289,7 +1293,7 @@ namespace OpenSim.Region.Framework.Scenes // REGION SYNC if (Scene.IsSyncedServer()) { - Scene.RegionSyncServerModule.DeleteObject(part.RegionHandle, part.LocalId); + Scene.RegionSyncServerModule.DeleteObject(part.RegionHandle, part.LocalId, part); //return; } Scene.ForEachScenePresence(delegate(ScenePresence avatar) @@ -3615,5 +3619,69 @@ namespace OpenSim.Region.Framework.Scenes } #endregion + +#region REGION SYNC + + //the LocX and LocY of the authoritative scene that this object is located + + private uint m_locX; + private uint m_locY; + public uint LocX + { + get { return m_locX; } + set { m_locX = value; } + } + public uint LocY + { + get { return m_locY; } + set { m_locY = value; } + } + + + //update the existing copy of the object with updated properties in 'updatedSog' + //TODO: handle updates on script content seperately (e.g. user edited the script and saved it). + public void UpdateObjectProperties(SceneObjectGroup updatedSog) + { + if (!this.GroupID.Equals(updatedSog.GroupID)) + return; + + //So far this function is written with Script Engine updating local Scene cache in mind. + + //We do not want to simply call SceneObjectGroup.Copy here to clone the object. + //We need to preserve the references to the prims (SceneObjectParts) inside the group, + //since their scripts are referencing back to the prims, and we have to update those + //references if we call SceneObjectGroup.Copy(), which creates new SceneObjectPart for all + //non root parts. (So is SceneObjectGroup.CopyPart().) + //Plus, we do not need to trigger client updating, since Script engine does not have client connections. + Dictionary updatedParts = new Dictionary(); + lock (m_parts) + { + foreach (KeyValuePair pair in updatedSog.Children){ + UUID partUUID = pair.Key; + SceneObjectPart updatedPart = pair.Value; + if(m_parts.ContainsKey(partUUID)){ + //update the existing part + SceneObjectPart oldPart = m_parts[partUUID]; + oldPart.UpdateObjectPartProperties(updatedPart); + updatedParts.Add(partUUID, updatedPart); + }else{ + //a new part + m_parts.Add(partUUID,updatedPart); + } + } + + //delete the parts that are no longer in the object-group + foreach(KeyValuePair pair in m_parts){ + if(!updatedParts.ContainsKey(pair.Key)){ + m_parts.Remove(pair.Key); + } + } + } + + //update the authoritative scene that this object is located, which is identified by (LocX, LocY) + this.m_locX = updatedSog.LocX; + this.m_locY = updatedSog.LocY; + } +#endregion } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index fa57f0b20b..2355a0c64b 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4734,5 +4734,60 @@ namespace OpenSim.Region.Framework.Scenes Color color = Color; return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A)); } + + #region REGION SYNC + + public void UpdateObjectPartProperties(SceneObjectPart updatedPart) + { + //So far this function is written with Script Engine updating local Scene cache in mind. + // + //Assumptions: + //(1) prim's UUID and LocalID won't change. + //(2) CreaterIF, OwnerID, GroupID, won't change + //For now, we only update a small set of properties, which is a subset of the serialized object data. + //We simply assume other properties won't change. (Just a temporary work-around.) + //Properties that will be updated: + //GroupPosition, OffsetPosition,RotationOffset, Velocity, AngularVelocity, Acceleration, + // 0 , Scale + // + //And we do not update Physics properties. + + //The above assumptions and limited updating actions can be easily fixed once Scene supports + //[property name, property value] type of detailed updates. + + //Need to be able to update TaskInventory, so that new scripts will be added + + if (updatedPart == null) + return; + + this.GroupPosition = updatedPart.GroupPosition; + this.OffsetPosition = updatedPart.OffsetPosition; + this.RotationOffset = updatedPart.RotationOffset; + this.AngularVelocity = updatedPart.AngularVelocity; + this.Acceleration = updatedPart.Acceleration; + this.Color = updatedPart.Color; + this.LinkNum = updatedPart.LinkNum; + this.Velocity = updatedPart.Velocity; + this.Scale = updatedPart.Scale; + this.SitAnimation = updatedPart.SitAnimation; + this.SitName = updatedPart.SitName; + this.SitTargetAvatar = updatedPart.SitTargetAvatar; + this.SitTargetOrientation = updatedPart.SitTargetOrientation; + this.SitTargetOrientationLL = updatedPart.SitTargetOrientationLL; + this.SitTargetPosition = updatedPart.SitTargetPosition; + this.SitTargetPositionLL = updatedPart.SitTargetPositionLL; + + this.ObjectFlags = updatedPart.ObjectFlags; + + this.m_inventory.Items = (TaskInventoryDictionary)updatedPart.m_inventory.Items.Clone(); + + //update shape information, for now, only update fileds in Shape whose set functions are defined in PrimitiveBaseShape + this.Shape = updatedPart.Shape.Copy(); + this.Shape.TextureEntry = updatedPart.Shape.TextureEntry; + + } + + #endregion + } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index b27dc59a1c..187118ba52 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -1061,5 +1061,34 @@ namespace OpenSim.Region.Framework.Scenes } } } + + #region REGION SYNC + public void SuspendScripts() + { + IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces(); + if (engines == null) + return; + + lock (m_items) + { + foreach (TaskInventoryItem item in m_items.Values) + { + if (item.InvType == (int)InventoryType.LSL) + { + foreach (IScriptModule engine in engines) + { + if (engine != null) + { + if (item.OwnerChanged) + engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER }); + item.OwnerChanged = false; + engine.SuspendScript(item.ItemID); + } + } + } + } + } + } + #endregion REGION SYNC } } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 532f7ef446..0739801a32 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -768,7 +768,7 @@ namespace OpenSim.Region.Framework.Scenes public void RegisterToEvents() { // REGION SYNC - if (!m_scene.IsSyncedServer())// || m_scene.RegionSyncEnabled == false) + if (m_scene.IsSyncedServer() || m_scene.RegionSyncEnabled == false) { // These client messages will not be handled by client managers but instead // they are caught by the RegionSyncClient module and passed up to the auth sim diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 5bdaa17f69..09dd745bc6 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -278,6 +278,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization //int time = System.Environment.TickCount; writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); + + //REGION SYNG + //Need to add LocX,LocY of the Scene that the object is located in. + //writer.WriteStartElement(String.Empty, "LocX", String.Empty); + //end of REGION SYGN + sceneObject.RootPart.ToXml(writer); writer.WriteStartElement(String.Empty, "OtherParts", String.Empty); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs index 8b2d387618..a6cf003f0b 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs @@ -120,6 +120,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests { throw new NotImplementedException(); } + + #region REGION SYNC + public List LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY) + { + return null; + } + #endregion REGION SYNC } public FakeStorageManager() : base(new FakeRegionDataStore()) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 417cef4e64..f4e08a46e3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -352,6 +352,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + #region LSL Util functions + // convert a LSL_Rotation to a Quaternion protected Quaternion Rot2Quaternion(LSL_Rotation r) { @@ -757,6 +759,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return rotBetween; } + #endregion //of LSL Util functions + public void llWhisper(int channelID, string text) { m_host.AddScriptLPS(1); @@ -1154,6 +1158,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return wind; } +#region REGION SYNC + + //REGION SYNC TOUCHED -- set via sync'ing with remote Scene public void llSetStatus(int status, int value) { m_host.AddScriptLPS(1); @@ -1329,6 +1336,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SetScale(m_host, scale); } + //REGION SYNC TOUCHED -- set via sync'ing with remote Scene protected void SetScale(SceneObjectPart part, LSL_Vector scale) { // TODO: this needs to trigger a persistance save as well @@ -1358,12 +1366,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (scale.z > World.m_maxNonphys) scale.z = World.m_maxNonphys; - Vector3 tmp = part.Scale; - tmp.X = (float)scale.x; - tmp.Y = (float)scale.y; - tmp.Z = (float)scale.z; - part.Scale = tmp; - part.SendFullUpdateToAllClients(); + if (World.ScriptEngineToSceneConnectorModule==null) + { + //If Script engine is local to Scene (REGION SYNC mode=server, and XEngine enabled=true, and no remote Script Engine connected) + Vector3 tmp = part.Scale; + tmp.X = (float)scale.x; + tmp.Y = (float)scale.y; + tmp.Z = (float)scale.z; + part.Scale = tmp; + part.SendFullUpdateToAllClients(); + } + else + { + //set via sync'ing with remote Scene + World.ScriptEngineToSceneConnectorModule.SendSetPrimProperties(part.ParentGroup.LocX, part.ParentGroup.LocY, part.UUID, "scale", scale); + } } public LSL_Vector llGetScale() @@ -1381,14 +1398,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } + //REGION SYNC TOUCHED -- set via sync'ing with remote Scene public void llSetColor(LSL_Vector color, int face) { m_host.AddScriptLPS(1); if (face == ScriptBaseClass.ALL_SIDES) face = SceneObjectPart.ALL_SIDES; - - m_host.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face); + + if (World.ScriptEngineToSceneConnectorModule == null) + { + m_host.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face); + } + else + { + object[] valParams = new object[2]; + //valParams[0] = (object)color.x; + //valParams[1] = (object)color.y; + //valParams[2] = (object)color.z; + Vector3 vcolor = new Vector3((float)color.x, (float)color.y, (float)color.z); + valParams[0] = (object)vcolor; + valParams[1] = (object)face; + World.ScriptEngineToSceneConnectorModule.SendSetPrimProperties(m_host.ParentGroup.LocX, m_host.ParentGroup.LocY, m_host.UUID, "color", (object)valParams); + } } public void SetTexGen(SceneObjectPart part, int face,int style) @@ -1897,12 +1929,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + //REGION SYNC TOUCHED -- set via sync'ing with remote Scene -- SetPos is modified. public void llSetPos(LSL_Vector pos) { m_host.AddScriptLPS(1); SetPos(m_host, pos); - + ScriptSleep(200); } @@ -1916,6 +1949,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return end; } + //REGION SYNC TOUCHED -- set via sync'ing with remote Scene protected void SetPos(SceneObjectPart part, LSL_Vector targetPos) { // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos) @@ -1930,16 +1964,39 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api targetPos.z = ground; SceneObjectGroup parent = part.ParentGroup; LSL_Vector real_vec = SetPosAdjust(currentPos, targetPos); - parent.UpdateGroupPosition(new Vector3((float)real_vec.x, (float)real_vec.y, (float)real_vec.z)); + //KittyL: edited below + if ((World.ScriptEngineToSceneConnectorModule == null)) + { + parent.UpdateGroupPosition(new Vector3((float)real_vec.x, (float)real_vec.y, (float)real_vec.z)); + } + else + { + object[] valParams = new object[1]; + Vector3 pos = new Vector3((float)real_vec.x, (float)real_vec.y, (float)real_vec.z); + valParams[0] = (Vector3)pos; + World.ScriptEngineToSceneConnectorModule.SendSetPrimProperties(m_host.ParentGroup.LocX, m_host.ParentGroup.LocY, m_host.UUID, "pos", (object)valParams); + } } else { if (llVecDist(new LSL_Vector(0,0,0), targetPos) <= 10.0f) { - part.OffsetPosition = new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z); - SceneObjectGroup parent = part.ParentGroup; - parent.HasGroupChanged = true; - parent.ScheduleGroupForTerseUpdate(); + //KittyL: edited below + if ((World.ScriptEngineToSceneConnectorModule == null)) + { + part.OffsetPosition = new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z); + SceneObjectGroup parent = part.ParentGroup; + parent.HasGroupChanged = true; + parent.ScheduleGroupForTerseUpdate(); + } + else + { + object[] valParams = new object[3]; + valParams[0] = (object)targetPos.x; + valParams[1] = (object)targetPos.y; + valParams[2] = (object)targetPos.z; + World.ScriptEngineToSceneConnectorModule.SendSetPrimProperties(m_host.ParentGroup.LocX, m_host.ParentGroup.LocY, m_host.UUID, "pos", (object)valParams); + } } } } @@ -2692,6 +2749,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScriptSleep(100); } + //REGION SYNC TOUCHED -- set via sync'ing with remote Scene public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param) { m_host.AddScriptLPS(1); @@ -2703,35 +2761,39 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (dist > m_ScriptDistanceFactor * 10.0f) return; - TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); - - foreach (KeyValuePair inv in partInventory) + if (World.ScriptEngineToSceneConnectorModule == null) { - if (inv.Value.Name == inventory) + //if Scene co-locates with Script Engine + + TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); + + foreach (KeyValuePair inv in partInventory) { - // make sure we're an object. - if (inv.Value.InvType != (int)InventoryType.Object) + if (inv.Value.Name == inventory) { - llSay(0, "Unable to create requested object. Object is missing from database."); - return; - } + // make sure we're an object. + if (inv.Value.InvType != (int)InventoryType.Object) + { + llSay(0, "Unable to create requested object. Object is missing from database."); + return; + } - Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z); - Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z); + Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z); + Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z); - // need the magnitude later - float velmag = (float)Util.GetMagnitude(llvel); + // need the magnitude later + float velmag = (float)Util.GetMagnitude(llvel); - SceneObjectGroup new_group = World.RezObject(m_host, inv.Value, llpos, Rot2Quaternion(rot), llvel, param); + SceneObjectGroup new_group = World.RezObject(m_host, inv.Value, llpos, Rot2Quaternion(rot), llvel, param); - // If either of these are null, then there was an unknown error. - if (new_group == null) - continue; - if (new_group.RootPart == null) - continue; + // If either of these are null, then there was an unknown error. + if (new_group == null) + continue; + if (new_group.RootPart == null) + continue; - // objects rezzed with this method are die_at_edge by default. - new_group.RootPart.SetDieAtEdge(true); + // objects rezzed with this method are die_at_edge by default. + new_group.RootPart.SetDieAtEdge(true); new_group.ResumeScripts(); @@ -2739,23 +2801,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api "object_rez", new Object[] { new LSL_String( new_group.RootPart.UUID.ToString()) }, - new DetectParams[0])); + new DetectParams[0])); - float groupmass = new_group.GetMass(); + float groupmass = new_group.GetMass(); - if (new_group.RootPart.PhysActor != null && new_group.RootPart.PhysActor.IsPhysical && llvel != Vector3.Zero) - { - //Recoil. - llApplyImpulse(new LSL_Vector(llvel.X * groupmass, llvel.Y * groupmass, llvel.Z * groupmass), 0); + if (new_group.RootPart.PhysActor != null && new_group.RootPart.PhysActor.IsPhysical && llvel != Vector3.Zero) + { + //Recoil. + llApplyImpulse(new LSL_Vector(llvel.X * groupmass, llvel.Y * groupmass, llvel.Z * groupmass), 0); + } + // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) + ScriptSleep((int)((groupmass * velmag) / 10)); + ScriptSleep(100); + return; } - // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) - ScriptSleep((int)((groupmass * velmag) / 10)); - ScriptSleep(100); - return; } - } - llSay(0, "Could not find object " + inventory); + llSay(0, "Could not find object " + inventory); + } + else + { + //Scene does not co-locate with Script Engine + Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z); + Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z); + Quaternion llrot = Rot2Quaternion(rot); + object[] valParams = new object[5]; + valParams[0] = (object)inventory; + valParams[1] = (object)llpos; + valParams[2] = (object)llpos; + valParams[3] = (object)llrot; + valParams[4] = (object)param; + //we borrow the implementation SendSetPrimProperties to send the message to Scene + World.ScriptEngineToSceneConnectorModule.SendSetPrimProperties(m_host.ParentGroup.LocX, m_host.ParentGroup.LocY, m_host.UUID, "object_rez", (object)valParams); + + // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) + //ScriptSleep((int)((groupmass * velmag) / 10)); + ScriptSleep(100); + } } public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param) @@ -6542,6 +6624,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return Util.SHA1Hash(src).ToLower(); } +#endregion REGION SYNC + protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist) { ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 02993856fd..a8eed284d8 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -322,6 +322,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning; m_Scene.EventManager.OnShutdown += OnShutdown; + //REGION SYNC events + m_Scene.EventManager.OnScriptEngineSyncStop += OnScriptEngineSyncStop; + //end REGION SYNC + if (m_SleepTime > 0) { m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance), @@ -1601,5 +1605,57 @@ namespace OpenSim.Region.ScriptEngine.XEngine instance.Resume(); } + + #region REGION SYNC functions + + //eventually triggered when user typed "sync stop" at the script engine's console + public void OnScriptEngineSyncStop() + { + //DoBackup(); + + //save the script states, stop script instances, and clear records + //similar to RemoveRegion(), except that still keep the engine in + //m_scriptEngines. + lock (m_Scripts) + { + foreach (IScriptInstance instance in m_Scripts.Values) + { + // Force a final state save + // + if (m_Assemblies.ContainsKey(instance.AssetID)) + { + string assembly = m_Assemblies[instance.AssetID]; + instance.SaveState(assembly); + } + + // Clear the event queue and abort the instance thread + // + instance.ClearQueue(); + instance.Stop(0); + + // Release events, timer, etc + // + instance.DestroyScriptInstance(); + + // Unload scripts and app domains + // Must be done explicitly because they have infinite + // lifetime + // + m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); + if (m_DomainScripts[instance.AppDomain].Count == 0) + { + m_DomainScripts.Remove(instance.AppDomain); + UnloadAppDomain(instance.AppDomain); + } + } + m_Scripts.Clear(); + m_PrimObjects.Clear(); + m_Assemblies.Clear(); + m_DomainScripts.Clear(); + } + + } + + #endregion } }