Merged with Kitty's Script engine code.

dsg
Dan Lake 2010-09-23 16:32:38 -07:00
parent 1c93854b47
commit f5d25981ac
27 changed files with 1238 additions and 87 deletions

View File

@ -1564,5 +1564,12 @@ VALUES
#endregion
#endregion
#region REGION SYNC
public List<SceneObjectGroup> LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY)
{
return null;
}
#endregion REGION SYNC
}
}

View File

@ -523,6 +523,148 @@ namespace OpenSim.Data.MySQL
return new List<SceneObjectGroup>(objects.Values);
}
#region REGION SYNC
public List<SceneObjectGroup> LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY)
{
const int ROWS_PER_QUERY = 5000;
Dictionary<UUID, SceneObjectPart> prims = new Dictionary<UUID, SceneObjectPart>(ROWS_PER_QUERY);
Dictionary<UUID, SceneObjectGroup> objects = new Dictionary<UUID, SceneObjectGroup>();
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<SceneObjectPart> primsWithInventory = new List<SceneObjectPart>();
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<SceneObjectGroup>(objects.Values);
}
#endregion REGION SYNC
/// <summary>
/// Load in a prim's persisted inventory.
/// </summary>

View File

@ -108,5 +108,12 @@ namespace OpenSim.Data.Null
public void Shutdown()
{
}
#region REGION SYNC
public List<SceneObjectGroup> LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY)
{
return null;
}
#endregion REGION SYNC
}
}

View File

@ -2332,5 +2332,11 @@ namespace OpenSim.Data.SQLite
}
}
#region REGION SYNC
public List<SceneObjectGroup> LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY)
{
return null;
}
#endregion REGION SYNC
}
}

View File

@ -2260,5 +2260,11 @@ namespace OpenSim.Data.SQLiteLegacy
}
}
#region REGION SYNC
public List<SceneObjectGroup> LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY)
{
return null;
}
#endregion REGION SYNC
}
}

View File

@ -359,8 +359,59 @@ namespace OpenSim
"kill uuid <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<Scene> 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)

View File

@ -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<string> m_inQ = new Queue<string>();
#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));

View File

@ -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
/// <summary>
/// A message for synchonization message between scenes
/// </summary>
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

View File

@ -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);
}
}
}

View File

@ -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<IRegionSyncServerModule>(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<UUID, ScenePresence> m_presenceUpdates = new Dictionary<UUID, ScenePresence>();
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);
}
}
}

View File

@ -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);
}
}

View File

@ -76,6 +76,10 @@ namespace OpenSim.Region.Framework.Interfaces
ArrayList GetScriptErrors(UUID itemID);
void ResumeScripts();
#region REGION SYNC
void SuspendScripts();
#endregion REGION SYNC
/// <summary>
/// Stop all the scripts in this entity.
/// </summary>

View File

@ -107,5 +107,9 @@ namespace OpenSim.Region.Framework.Interfaces
void StoreRegionWindlightSettings(RegionLightShareData wl);
void Shutdown();
#region REGION SYNC
List<SceneObjectGroup> LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY);
#endregion REGION SYNC
}
}

View File

@ -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);
}
}

View File

@ -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<Scene> localScenes);
public event PopulateLocalSceneList OnPopulateLocalSceneList;
public void TriggerPopulateLocalSceneList(List<Scene> localScenes)
//public delegate void PopulateLocalSceneList(List<Scene> localScenes, string[] cmdparams);
//public event PopulateLocalSceneList OnPopulateLocalSceneList;
//public void TriggerPopulateLocalSceneList(List<Scene> 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
}
}

View File

@ -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.
////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Capability originating call to update the asset of a script in a prim's (task's) inventory
/// </summary>
@ -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
/// <summary>
/// <see>CapsUpdateTaskInventoryScriptAsset(IClientAPI, UUID, UUID, bool, byte[])</see>
@ -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);
}

View File

@ -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; }
}
/// <summary>
/// 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.
/// </summary>
/// <param name="curLocX">the X coordinate of the scene's left-bottom corner</param>
/// <param name="curLocY">the Y coordinate of the scene's left-bottom corner</param>
/// <param name="offset">the offset position to the scene's left-bottom corner</param>
/// <returns></returns>
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<SceneObjectGroup> 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<IDialogModule>();
m_capsModule = RequestModuleInterface<ICapabilitiesModule>();
m_teleportModule = RequestModuleInterface<IEntityTransferModule>();
//REGION SYNC
RegionSyncServerModule = RequestModuleInterface<IRegionSyncServerModule>();
RegionSyncClientModule = RequestModuleInterface<IRegionSyncClientModule>();
ScriptEngineToSceneConnectorModule = RequestModuleInterface<IScriptEngineToSceneConnectorModule>();
// 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);
}
/// <summary>
@ -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

View File

@ -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);
@ -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
}
}

View File

@ -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
}
}

View File

@ -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<UUID, SceneObjectPart> updatedParts = new Dictionary<UUID, SceneObjectPart>();
lock (m_parts)
{
foreach (KeyValuePair<UUID, SceneObjectPart> 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<UUID, SceneObjectPart> 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
}
}

View File

@ -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,
//<Color /> <LinkNum>0</LinkNum> , 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
}
}

View File

@ -1061,5 +1061,34 @@ namespace OpenSim.Region.Framework.Scenes
}
}
}
#region REGION SYNC
public void SuspendScripts()
{
IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
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
}
}

View File

@ -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

View File

@ -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);

View File

@ -120,6 +120,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests
{
throw new NotImplementedException();
}
#region REGION SYNC
public List<SceneObjectGroup> LoadObjectsInGivenSpace(UUID regionID, float lowerX, float lowerY, float upperX, float upperY)
{
return null;
}
#endregion REGION SYNC
}
public FakeStorageManager() : base(new FakeRegionDataStore())

View File

@ -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,6 +1398,7 @@ 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);
@ -1388,7 +1406,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
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,6 +1929,7 @@ 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);
@ -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<UUID, TaskInventoryItem> 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<UUID, TaskInventoryItem> 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();

View File

@ -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
}
}