From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../World/AutoBackup/AutoBackupModule.cs | 791 ++++++--------------- .../World/AutoBackup/AutoBackupModuleState.cs | 70 +- .../World/MoneyModule/SampleMoneyModule.cs | 156 ++-- .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 181 ++++- .../Region/OptionalModules/World/NPC/NPCModule.cs | 99 ++- .../World/NPC/Tests/NPCModuleTests.cs | 8 +- .../World/SceneCommands/SceneCommandsModule.cs | 122 +--- .../World/TreePopulator/TreePopulatorModule.cs | 724 +++++++++++-------- 8 files changed, 1006 insertions(+), 1145 deletions(-) (limited to 'OpenSim/Region/OptionalModules/World') diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs index ceb3332..a14d819 100644 --- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs +++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs @@ -59,70 +59,58 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// /// /// Config Settings Documentation. - /// Each configuration setting can be specified in two places: OpenSim.ini or Regions.ini. - /// If specified in Regions.ini, the settings should be within the region's section name. - /// If specified in OpenSim.ini, the settings should be within the [AutoBackupModule] section. + /// Configuration setting can be specified in two places: OpenSim.ini and/or Regions.ini. + /// + /// OpenSim.ini only settings section [AutoBackupModule] + /// AutoBackupModuleEnabled: True/False. Default: False. If True, use the auto backup module. + /// if false module is disable and all rest is ignored + /// AutoBackupInterval: Double, non-negative value. Default: 720 (12 hours). + /// The number of minutes between each backup attempt. + /// AutoBackupDir: String. Default: "." (the current directory). + /// A directory (absolute or relative) where backups should be saved. + /// AutoBackupKeepFilesForDays remove files older than this number of days. 0 disables + /// + /// Next can be set on OpenSim.ini, as default, and or per region in Regions.ini /// Region-specific settings take precedence. /// - /// AutoBackupModuleEnabled: True/False. Default: False. If True, use the auto backup module. This setting does not support per-region basis. - /// All other settings under [AutoBackupModule] are ignored if AutoBackupModuleEnabled is false, even per-region settings! - /// AutoBackup: True/False. Default: False. If True, activate auto backup functionality. - /// This is the only required option for enabling auto-backup; the other options have sane defaults. - /// If False for a particular region, the auto-backup module becomes a no-op for the region, and all other AutoBackup* settings are ignored. - /// If False globally (the default), only regions that specifically override it in Regions.ini will get AutoBackup functionality. - /// AutoBackupInterval: Double, non-negative value. Default: 720 (12 hours). - /// The number of minutes between each backup attempt. - /// If a negative or zero value is given, it is equivalent to setting AutoBackup = False. - /// AutoBackupBusyCheck: True/False. Default: True. - /// If True, we will only take an auto-backup if a set of conditions are met. - /// These conditions are heuristics to try and avoid taking a backup when the sim is busy. + /// AutoBackup: True/False. Default: False. If True, activate auto backup functionality. + /// controls backup per region, with default optionaly set on OpenSim.ini + /// AutoBackupSkipAssets /// If true, assets are not saved to the oar file. Considerably reduces impact on simulator when backing up. Intended for when assets db is backed up separately /// AutoBackupKeepFilesForDays /// Backup files older than this value (in days) are deleted during the current backup process, 0 will disable this and keep all backup files indefinitely - /// AutoBackupScript: String. Default: not specified (disabled). + /// AutoBackupScript: String. Default: not specified (disabled). /// File path to an executable script or binary to run when an automatic backup is taken. /// The file should really be (Windows) an .exe or .bat, or (Linux/Mac) a shell script or binary. /// Trying to "run" directories, or things with weird file associations on Win32, might cause unexpected results! - /// argv[1] of the executed file/script will be the file name of the generated OAR. + /// argv[1] of the executed file/script will be the file name of the generated OAR. /// If the process can't be spawned for some reason (file not found, no execute permission, etc), write a warning to the console. /// AutoBackupNaming: string. Default: Time. /// One of three strings (case insensitive): /// "Time": Current timestamp is appended to file name. An existing file will never be overwritten. - /// "Sequential": A number is appended to the file name. So if RegionName_x.oar exists, we'll save to RegionName_{x+1}.oar next. An existing file will never be overwritten. - /// "Overwrite": Always save to file named "${AutoBackupDir}/RegionName.oar", even if we have to overwrite an existing file. - /// AutoBackupDir: String. Default: "." (the current directory). - /// A directory (absolute or relative) where backups should be saved. - /// AutoBackupDilationThreshold: float. Default: 0.5. Lower bound on time dilation required for BusyCheck heuristics to pass. - /// If the time dilation is below this value, don't take a backup right now. - /// AutoBackupAgentThreshold: int. Default: 10. Upper bound on # of agents in region required for BusyCheck heuristics to pass. - /// If the number of agents is greater than this value, don't take a backup right now - /// Save memory by setting low initial capacities. Minimizes impact in common cases of all regions using same interval, and instances hosting 1 ~ 4 regions. - /// Also helps if you don't want AutoBackup at all. + /// "Sequential": A number is appended to the file name. So if RegionName_x.oar exists, we'll save to RegionName_{x+1}.oar next. An existing file will never be overwritten. + /// "Overwrite": Always save to file named "${AutoBackupDir}/RegionName.oar", even if we have to overwrite an existing file. /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AutoBackupModule")] public class AutoBackupModule : ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private readonly Dictionary m_pendingSaves = new Dictionary(1); private readonly AutoBackupModuleState m_defaultState = new AutoBackupModuleState(); private readonly Dictionary m_states = new Dictionary(1); - private readonly Dictionary> m_timerMap = - new Dictionary>(1); - private readonly Dictionary m_timers = new Dictionary(1); private delegate T DefaultGetter(string settingName, T defaultValue); private bool m_enabled; private ICommandConsole m_console; private List m_Scenes = new List (); - - - /// - /// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState! - /// - private bool m_closed; + private Timer m_masterTimer; + private bool m_busy; + private int m_KeepFilesForDays = -1; + private string m_backupDir; + private bool m_doneFirst; + private double m_baseInterval; private IConfigSource m_configSource; @@ -159,36 +147,38 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup void IRegionModuleBase.Initialise(IConfigSource source) { // Determine if we have been enabled at all in OpenSim.ini -- this is part and parcel of being an optional module - this.m_configSource = source; + m_configSource = source; IConfig moduleConfig = source.Configs["AutoBackupModule"]; if (moduleConfig == null) { - this.m_enabled = false; + m_enabled = false; return; } - else - { - this.m_enabled = moduleConfig.GetBoolean("AutoBackupModuleEnabled", false); - if (this.m_enabled) - { - m_log.Info("[AUTO BACKUP]: AutoBackupModule enabled"); - } - else - { - return; - } - } - Timer defTimer = new Timer(43200000); - this.m_defaultState.Timer = defTimer; - this.m_timers.Add(43200000, defTimer); - defTimer.Elapsed += this.HandleElapsed; - defTimer.AutoReset = true; - defTimer.Start(); + m_enabled = moduleConfig.GetBoolean("AutoBackupModuleEnabled", false); + if(!m_enabled) + return; + + ParseDefaultConfig(moduleConfig); + if(!m_enabled) + return; + + m_log.Debug("[AUTO BACKUP]: Default config:"); + m_log.Debug(m_defaultState.ToString()); + + m_log.Info("[AUTO BACKUP]: AutoBackupModule enabled"); + m_masterTimer = new Timer(); + m_masterTimer.Interval = m_baseInterval; + m_masterTimer.Elapsed += HandleElapsed; + m_masterTimer.AutoReset = false; + + m_console = MainConsole.Instance; - AutoBackupModuleState abms = this.ParseConfig(null, true); - m_log.Debug("[AUTO BACKUP]: Here is the default config:"); - m_log.Debug(abms.ToString()); + m_console.Commands.AddCommand ( + "AutoBackup", true, "dooarbackup", + "dooarbackup | ALL", + "saves the single region to a oar or ALL regions in instance to oars, using same settings as AutoBackup. Note it restarts time interval", DoBackup); + m_busy = true; } /// @@ -196,13 +186,11 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// void IRegionModuleBase.Close() { - if (!this.m_enabled) - { + if (!m_enabled) return; - } // We don't want any timers firing while the sim's coming down; strange things may happen. - this.StopAllTimers(); + m_masterTimer.Dispose(); } /// @@ -211,18 +199,11 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// void IRegionModuleBase.AddRegion (Scene scene) { - if (!this.m_enabled) { + if (!m_enabled) return; - } - lock (m_Scenes) { - m_Scenes.Add (scene); - } - m_console = MainConsole.Instance; - m_console.Commands.AddCommand ( - "AutoBackup", false, "dobackup", - "dobackup", - "do backup.", DoBackup); + lock (m_Scenes) + m_Scenes.Add (scene); } /// @@ -231,28 +212,14 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// The scene (region) to stop performing AutoBackup on. void IRegionModuleBase.RemoveRegion(Scene scene) { - if (!this.m_enabled) - { + if (m_enabled) return; - } - m_Scenes.Remove (scene); - if (this.m_states.ContainsKey(scene)) - { - AutoBackupModuleState abms = this.m_states[scene]; - // Remove this scene out of the timer map list - Timer timer = abms.Timer; - List list = this.m_timerMap[timer]; - list.Remove(scene); - - // Shut down the timer if this was the last scene for the timer - if (list.Count == 0) - { - this.m_timerMap.Remove(timer); - this.m_timers.Remove(timer.Interval); - timer.Close(); - } - this.m_states.Remove(scene); + lock(m_Scenes) + { + if (m_states.ContainsKey(scene)) + m_states.Remove(scene); + m_Scenes.Remove(scene); } } @@ -263,22 +230,29 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// The scene to (possibly) perform AutoBackup on. void IRegionModuleBase.RegionLoaded(Scene scene) { - if (!this.m_enabled) - { + if (!m_enabled) return; - } // This really ought not to happen, but just in case, let's pretend it didn't... if (scene == null) - { return; - } - AutoBackupModuleState abms = this.ParseConfig(scene, false); - m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName); - m_log.Debug((abms == null ? "DEFAULT" : abms.ToString())); + AutoBackupModuleState abms = ParseConfig(scene); + if(abms == null) + { + m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName); + m_log.Debug("DEFAULT"); + abms = new AutoBackupModuleState(m_defaultState); + } + else + { + m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName); + m_log.Debug(abms.ToString()); + } m_states.Add(scene, abms); + m_busy = false; + m_masterTimer.Start(); } /// @@ -292,356 +266,174 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup private void DoBackup (string module, string[] args) { - if (args.Length != 2) { - MainConsole.Instance.OutputFormat ("Usage: dobackup "); + if (!m_enabled) return; - } - bool found = false; - string name = args [1]; - lock (m_Scenes) { - foreach (Scene s in m_Scenes) { - string test = s.Name.ToString (); - if (test == name) { - found = true; - DoRegionBackup (s); - } - } - if (!found) { - MainConsole.Instance.OutputFormat ("No such region {0}. Nothing to backup", name); - } - } - } - /// - /// Set up internal state for a given scene. Fairly complex code. - /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene. - /// - /// The scene to look at. - /// Whether this call is intended to figure out what we consider the "default" config (applied to all regions unless overridden by per-region settings). - /// An AutoBackupModuleState contains most information you should need to know relevant to auto-backup, as applicable to a single region. - private AutoBackupModuleState ParseConfig(IScene scene, bool parseDefault) - { - string sRegionName; - string sRegionLabel; -// string prepend; - AutoBackupModuleState state; - - if (parseDefault) - { - sRegionName = null; - sRegionLabel = "DEFAULT"; -// prepend = ""; - state = this.m_defaultState; - } - else - { - sRegionName = scene.RegionInfo.RegionName; - sRegionLabel = sRegionName; -// prepend = sRegionName + "."; - state = null; - } - - // Read the config settings and set variables. - IConfig regionConfig = (scene != null ? scene.Config.Configs[sRegionName] : null); - IConfig config = this.m_configSource.Configs["AutoBackupModule"]; - if (config == null) + if (args.Length != 2) { - // defaultState would be disabled too if the section doesn't exist. - state = this.m_defaultState; - return state; - } - - bool tmpEnabled = ResolveBoolean("AutoBackup", this.m_defaultState.Enabled, config, regionConfig); - if (state == null && tmpEnabled != this.m_defaultState.Enabled) - //Varies from default state - { - state = new AutoBackupModuleState(); + MainConsole.Instance.OutputFormat ("Usage: dooarbackup "); + return; } - if (state != null) + if(m_busy) { - state.Enabled = tmpEnabled; + MainConsole.Instance.OutputFormat ("Already doing a backup, please try later"); + return; } - // If you don't want AutoBackup, we stop. - if ((state == null && !this.m_defaultState.Enabled) || (state != null && !state.Enabled)) - { - return state; - } - else - { - m_log.Info("[AUTO BACKUP]: Region " + sRegionLabel + " is AutoBackup ENABLED."); - } + m_masterTimer.Stop(); + m_busy = true; - // Borrow an existing timer if one exists for the same interval; otherwise, make a new one. - double interval = - this.ResolveDouble("AutoBackupInterval", this.m_defaultState.IntervalMinutes, - config, regionConfig) * 60000.0; - if (state == null && interval != this.m_defaultState.IntervalMinutes * 60000.0) - { - state = new AutoBackupModuleState(); - } + bool found = false; + string name = args [1]; + Scene[] scenes; + lock (m_Scenes) + scenes = m_Scenes.ToArray(); - if (this.m_timers.ContainsKey(interval)) - { - if (state != null) - { - state.Timer = this.m_timers[interval]; - } - m_log.Debug("[AUTO BACKUP]: Reusing timer for " + interval + " msec for region " + - sRegionLabel); - } - else - { - // 0 or negative interval == do nothing. - if (interval <= 0.0 && state != null) - { - state.Enabled = false; - return state; - } - if (state == null) - { - state = new AutoBackupModuleState(); - } - Timer tim = new Timer(interval); - state.Timer = tim; - //Milliseconds -> minutes - this.m_timers.Add(interval, tim); - tim.Elapsed += this.HandleElapsed; - tim.AutoReset = true; - tim.Start(); - } + if(scenes == null) + return; - // Add the current region to the list of regions tied to this timer. - if (scene != null) + Scene s; + try { - if (state != null) + if(name == "ALL") { - if (this.m_timerMap.ContainsKey(state.Timer)) + for(int i = 0; i < scenes.Length; i++) { - this.m_timerMap[state.Timer].Add(scene); - } - else - { - List scns = new List(1); - scns.Add(scene); - this.m_timerMap.Add(state.Timer, scns); + s = scenes[i]; + DoRegionBackup(s); + if (!m_enabled) + return; } + return; } - else + + for(int i = 0; i < scenes.Length; i++) { - if (this.m_timerMap.ContainsKey(this.m_defaultState.Timer)) + s = scenes[i]; + if (s.Name == name) { - this.m_timerMap[this.m_defaultState.Timer].Add(scene); - } - else - { - List scns = new List(1); - scns.Add(scene); - this.m_timerMap.Add(this.m_defaultState.Timer, scns); + found = true; + DoRegionBackup(s); + break; } } } - - bool tmpBusyCheck = ResolveBoolean("AutoBackupBusyCheck", - this.m_defaultState.BusyCheck, config, regionConfig); - if (state == null && tmpBusyCheck != this.m_defaultState.BusyCheck) + catch { } + finally { - state = new AutoBackupModuleState(); - } + if (m_enabled) + m_masterTimer.Start(); + m_busy = false; + } + if (!found) + MainConsole.Instance.OutputFormat ("No such region {0}. Nothing to backup", name); + } - if (state != null) - { - state.BusyCheck = tmpBusyCheck; - } + private void ParseDefaultConfig(IConfig config) + { - // Included Option To Skip Assets - bool tmpSkipAssets = ResolveBoolean("AutoBackupSkipAssets", - this.m_defaultState.SkipAssets, config, regionConfig); - if (state == null && tmpSkipAssets != this.m_defaultState.SkipAssets) + m_backupDir = "."; + string backupDir = config.GetString("AutoBackupDir", "."); + if (backupDir != ".") { - state = new AutoBackupModuleState(); + try + { + DirectoryInfo dirinfo = new DirectoryInfo(backupDir); + if (!dirinfo.Exists) + dirinfo.Create(); + } + catch (Exception e) + { + m_enabled = false; + m_log.WarnFormat("[AUTO BACKUP]: Error accessing backup folder {0}. Module disabled. {1}", + backupDir, e); + return; + } } + m_backupDir = backupDir; - if (state != null) - { - state.SkipAssets = tmpSkipAssets; - } + double interval = config.GetDouble("AutoBackupInterval", 720); + interval *= 60000.0; + m_baseInterval = interval; // How long to keep backup files in days, 0 Disables this feature - int tmpKeepFilesForDays = ResolveInt("AutoBackupKeepFilesForDays", - this.m_defaultState.KeepFilesForDays, config, regionConfig); - if (state == null && tmpKeepFilesForDays != this.m_defaultState.KeepFilesForDays) - { - state = new AutoBackupModuleState(); - } + m_KeepFilesForDays = config.GetInt("AutoBackupKeepFilesForDays",m_KeepFilesForDays); - if (state != null) - { - state.KeepFilesForDays = tmpKeepFilesForDays; - } + m_defaultState.Enabled = config.GetBoolean("AutoBackup", m_defaultState.Enabled); + + m_defaultState.SkipAssets = config.GetBoolean("AutoBackupSkipAssets",m_defaultState.SkipAssets); // Set file naming algorithm - string stmpNamingType = ResolveString("AutoBackupNaming", - this.m_defaultState.NamingType.ToString(), config, regionConfig); + string stmpNamingType = config.GetString("AutoBackupNaming", m_defaultState.NamingType.ToString()); NamingType tmpNamingType; if (stmpNamingType.Equals("Time", StringComparison.CurrentCultureIgnoreCase)) - { tmpNamingType = NamingType.Time; - } else if (stmpNamingType.Equals("Sequential", StringComparison.CurrentCultureIgnoreCase)) - { tmpNamingType = NamingType.Sequential; - } else if (stmpNamingType.Equals("Overwrite", StringComparison.CurrentCultureIgnoreCase)) - { tmpNamingType = NamingType.Overwrite; - } else { - m_log.Warn("Unknown naming type specified for region " + sRegionLabel + ": " + - stmpNamingType); + m_log.Warn("Unknown naming type specified for Default"); tmpNamingType = NamingType.Time; } + m_defaultState.NamingType = tmpNamingType; - if (state == null && tmpNamingType != this.m_defaultState.NamingType) - { - state = new AutoBackupModuleState(); - } + m_defaultState.Script = config.GetString("AutoBackupScript", m_defaultState.Script); - if (state != null) - { - state.NamingType = tmpNamingType; - } + } - string tmpScript = ResolveString("AutoBackupScript", - this.m_defaultState.Script, config, regionConfig); - if (state == null && tmpScript != this.m_defaultState.Script) - { - state = new AutoBackupModuleState(); - } + /// + /// Set up internal state for a given scene. Fairly complex code. + /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene. + /// + /// The scene to look at. + /// Whether this call is intended to figure out what we consider the "default" config (applied to all regions unless overridden by per-region settings). + /// An AutoBackupModuleState contains most information you should need to know relevant to auto-backup, as applicable to a single region. + private AutoBackupModuleState ParseConfig(IScene scene) + { + if(scene == null) + return null; - if (state != null) - { - state.Script = tmpScript; - } + string sRegionName; + AutoBackupModuleState state = null; - string tmpBackupDir = ResolveString("AutoBackupDir", ".", config, regionConfig); - if (state == null && tmpBackupDir != this.m_defaultState.BackupDir) - { - state = new AutoBackupModuleState(); - } + sRegionName = scene.RegionInfo.RegionName; - if (state != null) - { - state.BackupDir = tmpBackupDir; - // Let's give the user some convenience and auto-mkdir - if (state.BackupDir != ".") - { - try - { - DirectoryInfo dirinfo = new DirectoryInfo(state.BackupDir); - if (!dirinfo.Exists) - { - dirinfo.Create(); - } - } - catch (Exception e) - { - m_log.Warn( - "[AUTO BACKUP]: BAD NEWS. You won't be able to save backups to directory " + - state.BackupDir + - " because it doesn't exist or there's a permissions issue with it. Here's the exception.", - e); - } - } - } + // Read the config settings and set variables. + IConfig regionConfig = scene.Config.Configs[sRegionName]; + if (regionConfig == null) + return null; - if(state == null) - return m_defaultState; + state = new AutoBackupModuleState(); - return state; - } + state.Enabled = regionConfig.GetBoolean("AutoBackup", m_defaultState.Enabled); - /// - /// Helper function for ParseConfig. - /// - /// - /// - /// - /// - /// - private bool ResolveBoolean(string settingName, bool defaultValue, IConfig global, IConfig local) - { - if(local != null) - { - return local.GetBoolean(settingName, global.GetBoolean(settingName, defaultValue)); - } - else - { - return global.GetBoolean(settingName, defaultValue); - } - } + // Included Option To Skip Assets + state.SkipAssets = regionConfig.GetBoolean("AutoBackupSkipAssets", m_defaultState.SkipAssets); - /// - /// Helper function for ParseConfig. - /// - /// - /// - /// - /// - /// - private double ResolveDouble(string settingName, double defaultValue, IConfig global, IConfig local) - { - if (local != null) - { - return local.GetDouble(settingName, global.GetDouble(settingName, defaultValue)); - } + // Set file naming algorithm + string stmpNamingType = regionConfig.GetString("AutoBackupNaming", m_defaultState.NamingType.ToString()); + NamingType tmpNamingType; + if (stmpNamingType.Equals("Time", StringComparison.CurrentCultureIgnoreCase)) + tmpNamingType = NamingType.Time; + else if (stmpNamingType.Equals("Sequential", StringComparison.CurrentCultureIgnoreCase)) + tmpNamingType = NamingType.Sequential; + else if (stmpNamingType.Equals("Overwrite", StringComparison.CurrentCultureIgnoreCase)) + tmpNamingType = NamingType.Overwrite; else { - return global.GetDouble(settingName, defaultValue); + m_log.Warn("Unknown naming type specified for region " + sRegionName + ": " + + stmpNamingType); + tmpNamingType = NamingType.Time; } - } + m_defaultState.NamingType = tmpNamingType; - /// - /// Helper function for ParseConfig. - /// - /// - /// - /// - /// - /// - private int ResolveInt(string settingName, int defaultValue, IConfig global, IConfig local) - { - if (local != null) - { - return local.GetInt(settingName, global.GetInt(settingName, defaultValue)); - } - else - { - return global.GetInt(settingName, defaultValue); - } + state.Script = regionConfig.GetString("AutoBackupScript", m_defaultState.Script); + return state; } - /// - /// Helper function for ParseConfig. - /// - /// - /// - /// - /// - /// - private string ResolveString(string settingName, string defaultValue, IConfig global, IConfig local) - { - if (local != null) - { - return local.GetString(settingName, global.GetString(settingName, defaultValue)); - } - else - { - return global.GetString(settingName, defaultValue); - } - } /// /// Called when any auto-backup timer expires. This starts the code path for actually performing a backup. @@ -650,63 +442,27 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// private void HandleElapsed(object sender, ElapsedEventArgs e) { - // TODO: heuristic thresholds are per-region, so we should probably run heuristics once per region - // XXX: Running heuristics once per region could add undue performance penalty for something that's supposed to - // check whether the region is too busy! Especially on sims with LOTS of regions. - // Alternative: make heuristics thresholds global to the module rather than per-region. Less flexible, - // but would allow us to be semantically correct while being easier on perf. - // Alternative 2: Run heuristics once per unique set of heuristics threshold parameters! Ay yi yi... - // Alternative 3: Don't support per-region heuristics at all; just accept them as a global only parameter. - // Since this is pretty experimental, I haven't decided which alternative makes the most sense. - if (this.m_closed) - { + if (!m_enabled || m_busy) return; - } - bool heuristicsRun = false; - bool heuristicsPassed = false; - if (!this.m_timerMap.ContainsKey((Timer) sender)) + + m_busy = true; + if(m_doneFirst && m_KeepFilesForDays > 0) + RemoveOldFiles(); + + foreach (IScene scene in m_Scenes) { - m_log.Debug("[AUTO BACKUP]: Code-up error: timerMap doesn't contain timer " + sender); + if (!m_enabled) + return; + DoRegionBackup(scene); } - List tmap = this.m_timerMap[(Timer) sender]; - if (tmap != null && tmap.Count > 0) + if (m_enabled) { - foreach (IScene scene in tmap) - { - AutoBackupModuleState state = this.m_states[scene]; - bool heuristics = state.BusyCheck; - - // Fast path: heuristics are on; already ran em; and sim is fine; OR, no heuristics for the region. - if ((heuristics && heuristicsRun && heuristicsPassed) || !heuristics) - { - this.DoRegionBackup(scene); - // Heuristics are on; ran but we're too busy -- keep going. Maybe another region will have heuristics off! - } - else if (heuristicsRun) - { - m_log.Info("[AUTO BACKUP]: Heuristics: too busy to backup " + - scene.RegionInfo.RegionName + " right now."); - continue; - // Logical Deduction: heuristics are on but haven't been run - } - else - { - heuristicsPassed = this.RunHeuristics(scene); - heuristicsRun = true; - if (!heuristicsPassed) - { - m_log.Info("[AUTO BACKUP]: Heuristics: too busy to backup " + - scene.RegionInfo.RegionName + " right now."); - continue; - } - this.DoRegionBackup(scene); - } - - // Remove Old Backups - this.RemoveOldFiles(state); - } + m_masterTimer.Start(); + m_busy = false; } + + m_doneFirst = true; } /// @@ -723,21 +479,29 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup return; } - AutoBackupModuleState state = this.m_states[scene]; + m_busy = true; + + AutoBackupModuleState state; + if(!m_states.TryGetValue(scene, out state)) + return; + + if(state == null || !state.Enabled) + return; + IRegionArchiverModule iram = scene.RequestModuleInterface(); + if(iram == null) + return; + string savePath = BuildOarPath(scene.RegionInfo.RegionName, - state.BackupDir, + m_backupDir, state.NamingType); if (savePath == null) { m_log.Warn("[AUTO BACKUP]: savePath is null in HandleElapsed"); return; } - Guid guid = Guid.NewGuid(); - m_pendingSaves.Add(guid, scene); - state.LiveRequests.Add(guid, savePath); - ((Scene) scene).EventManager.OnOarFileSaved += new EventManager.OarFileSaved(EventManager_OnOarFileSaved); + Guid guid = Guid.NewGuid(); m_log.Info("[AUTO BACKUP]: Backing up region " + scene.RegionInfo.RegionName); // Must pass options, even if dictionary is empty! @@ -747,47 +511,37 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup options["noassets"] = true; iram.ArchiveRegion(savePath, guid, options); + ExecuteScript(state.Script, savePath); } // For the given state, remove backup files older than the states KeepFilesForDays property - private void RemoveOldFiles(AutoBackupModuleState state) + private void RemoveOldFiles() { - // 0 Means Disabled, Keep Files Indefinitely - if (state.KeepFilesForDays > 0) + string[] files; + try { - string[] files = Directory.GetFiles(state.BackupDir, "*.oar"); - DateTime CuttOffDate = DateTime.Now.AddDays(0 - state.KeepFilesForDays); - - foreach (string file in files) - { - try - { - FileInfo fi = new FileInfo(file); - if (fi.CreationTime < CuttOffDate) - fi.Delete(); - } - catch (Exception Ex) - { - m_log.Error("[AUTO BACKUP]: Error deleting old backup file '" + file + "': " + Ex.Message); - } - } + files = Directory.GetFiles(m_backupDir, "*.oar"); + } + catch (Exception Ex) + { + m_log.Error("[AUTO BACKUP]: Error reading backup folder " + m_backupDir + ": " + Ex.Message); + return; } - } - /// - /// Called by the Event Manager when the OnOarFileSaved event is fired. - /// - /// - /// - void EventManager_OnOarFileSaved(Guid guid, string message) - { - // Ignore if the OAR save is being done by some other part of the system - if (m_pendingSaves.ContainsKey(guid)) + DateTime CuttOffDate = DateTime.Now.AddDays(-m_KeepFilesForDays); + + foreach (string file in files) { - AutoBackupModuleState abms = m_states[(m_pendingSaves[guid])]; - ExecuteScript(abms.Script, abms.LiveRequests[guid]); - m_pendingSaves.Remove(guid); - abms.LiveRequests.Remove(guid); + try + { + FileInfo fi = new FileInfo(file); + if (fi.CreationTime < CuttOffDate) + fi.Delete(); + } + catch (Exception Ex) + { + m_log.Error("[AUTO BACKUP]: Error deleting old backup file '" + file + "': " + Ex.Message); + } } } @@ -817,63 +571,6 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup return output; } - /// Return value of true ==> not too busy; false ==> too busy to backup an OAR right now, or error. - private bool RunHeuristics(IScene region) - { - try - { - return this.RunTimeDilationHeuristic(region) && this.RunAgentLimitHeuristic(region); - } - catch (Exception e) - { - m_log.Warn("[AUTO BACKUP]: Exception in RunHeuristics", e); - return false; - } - } - - /// - /// If the time dilation right at this instant is less than the threshold specified in AutoBackupDilationThreshold (default 0.5), - /// then we return false and trip the busy heuristic's "too busy" path (i.e. don't save an OAR). - /// AutoBackupDilationThreshold is a _LOWER BOUND_. Lower Time Dilation is bad, so if you go lower than our threshold, it's "too busy". - /// - /// - /// Returns true if we're not too busy; false means we've got worse time dilation than the threshold. - private bool RunTimeDilationHeuristic(IScene region) - { - string regionName = region.RegionInfo.RegionName; - return region.TimeDilation >= - this.m_configSource.Configs["AutoBackupModule"].GetFloat( - regionName + ".AutoBackupDilationThreshold", 0.5f); - } - - /// - /// If the root agent count right at this instant is less than the threshold specified in AutoBackupAgentThreshold (default 10), - /// then we return false and trip the busy heuristic's "too busy" path (i.e., don't save an OAR). - /// AutoBackupAgentThreshold is an _UPPER BOUND_. Higher Agent Count is bad, so if you go higher than our threshold, it's "too busy". - /// - /// - /// Returns true if we're not too busy; false means we've got more agents on the sim than the threshold. - private bool RunAgentLimitHeuristic(IScene region) - { - string regionName = region.RegionInfo.RegionName; - try - { - Scene scene = (Scene) region; - // TODO: Why isn't GetRootAgentCount() a method in the IScene interface? Seems generally useful... - return scene.GetRootAgentCount() <= - this.m_configSource.Configs["AutoBackupModule"].GetInt( - regionName + ".AutoBackupAgentThreshold", 10); - } - catch (InvalidCastException ice) - { - m_log.Debug( - "[AUTO BACKUP]: I NEED MAINTENANCE: IScene is not a Scene; can't get root agent count!", - ice); - return true; - // Non-obstructionist safest answer... - } - } - /// /// Run the script or executable specified by the "AutoBackupScript" config setting. /// Of course this is a security risk if you let anyone modify OpenSim.ini and they want to run some nasty bash script. @@ -920,18 +617,6 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup } /// - /// Quickly stop all timers from firing. - /// - private void StopAllTimers() - { - foreach (Timer t in this.m_timerMap.Keys) - { - t.Close(); - } - this.m_closed = true; - } - - /// /// Determine the next unique filename by number, for "Sequential" AutoBackupNamingType. /// /// @@ -1033,5 +718,3 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup } } } - - diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs index ce7c368..fb87677 100644 --- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs +++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs @@ -35,29 +35,23 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// If you use this class in any way outside of AutoBackupModule, you should treat the class as opaque. /// Since it is not part of the framework, you really should not rely upon it outside of the AutoBackupModule implementation. /// - /// + /// public class AutoBackupModuleState { - private Dictionary m_liveRequests = null; - public AutoBackupModuleState() { - this.Enabled = false; - this.BackupDir = "."; - this.BusyCheck = true; - this.SkipAssets = false; - this.Timer = null; - this.NamingType = NamingType.Time; - this.Script = null; - this.KeepFilesForDays = 0; + Enabled = false; + SkipAssets = false; + NamingType = NamingType.Time; + Script = null; } - public Dictionary LiveRequests + public AutoBackupModuleState(AutoBackupModuleState copyFrom) { - get { - return this.m_liveRequests ?? - (this.m_liveRequests = new Dictionary(1)); - } + Enabled = copyFrom.Enabled; + SkipAssets = copyFrom.SkipAssets; + NamingType = copyFrom.NamingType; + Script = copyFrom.Script; } public bool Enabled @@ -66,33 +60,6 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup set; } - public System.Timers.Timer Timer - { - get; - set; - } - - public double IntervalMinutes - { - get - { - if (this.Timer == null) - { - return -1.0; - } - else - { - return this.Timer.Interval / 60000.0; - } - } - } - - public bool BusyCheck - { - get; - set; - } - public bool SkipAssets { get; @@ -105,36 +72,19 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup set; } - public string BackupDir - { - get; - set; - } - public NamingType NamingType { get; set; } - public int KeepFilesForDays - { - get; - set; - } - public new string ToString() { string retval = ""; - retval += "[AUTO BACKUP]: AutoBackup: " + (Enabled ? "ENABLED" : "DISABLED") + "\n"; - retval += "[AUTO BACKUP]: Interval: " + IntervalMinutes + " minutes" + "\n"; - retval += "[AUTO BACKUP]: Do Busy Check: " + (BusyCheck ? "Yes" : "No") + "\n"; retval += "[AUTO BACKUP]: Naming Type: " + NamingType.ToString() + "\n"; - retval += "[AUTO BACKUP]: Backup Dir: " + BackupDir + "\n"; retval += "[AUTO BACKUP]: Script: " + Script + "\n"; return retval; } } } - diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs index 5f47810..b32a429 100644 --- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs +++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs @@ -65,10 +65,10 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// // private UUID EconomyBaseAccount = UUID.Zero; - private float EnergyEfficiency = 0f; + private float EnergyEfficiency = 1f; // private ObjectPaid handerOnObjectPaid; private bool m_enabled = true; - private bool m_sellEnabled = false; + private bool m_sellEnabled = true; private IConfigSource m_gConfig; @@ -85,12 +85,12 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule private int ObjectCount = 0; private int PriceEnergyUnit = 0; - private int PriceGroupCreate = 0; + private int PriceGroupCreate = -1; private int PriceObjectClaim = 0; private float PriceObjectRent = 0f; - private float PriceObjectScaleFactor = 0f; + private float PriceObjectScaleFactor = 10f; private int PriceParcelClaim = 0; - private float PriceParcelClaimFactor = 0f; + private float PriceParcelClaimFactor = 1f; private int PriceParcelRent = 0; private int PricePublicObjectDecay = 0; private int PricePublicObjectDelete = 0; @@ -98,7 +98,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule private int PriceUpload = 0; private int TeleportMinPrice = 0; - private float TeleportPriceExponent = 0f; + private float TeleportPriceExponent = 2f; #region IMoneyModule Members @@ -124,13 +124,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule public void Initialise(IConfigSource config) { m_gConfig = config; - - IConfig startupConfig = m_gConfig.Configs["Startup"]; - IConfig economyConfig = m_gConfig.Configs["Economy"]; - - - ReadConfigAndPopulate(startupConfig, "Startup"); - ReadConfigAndPopulate(economyConfig, "Economy"); + ReadConfigAndPopulate(); } public void AddRegion(Scene scene) @@ -151,13 +145,13 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule // to the command line parameters you use to start up your client // This commonly looks like -helperuri http://127.0.0.1:9000/ - + // Local Server.. enables functionality only. httpServer.AddXmlRPCHandler("getCurrencyQuote", quote_func); httpServer.AddXmlRPCHandler("buyCurrency", buy_func); httpServer.AddXmlRPCHandler("preflightBuyLandPrep", preflightBuyLandPrep_func); httpServer.AddXmlRPCHandler("buyLandPrep", landBuy_func); - + } if (m_scenel.ContainsKey(scene.RegionInfo.RegionHandle)) @@ -205,13 +199,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule { } - public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount) + public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount, UUID txn, out string result) { + result = String.Empty; string description = String.Format("Object {0} pays {1}", resolveObjectName(objectID), resolveAgentName(toID)); bool give_result = doMoneyTransfer(fromID, toID, amount, 2, description); - + BalanceUpdate(fromID, toID, give_result, description); return give_result; @@ -240,35 +235,51 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// /// Parse Configuration /// - /// - /// - /// - private void ReadConfigAndPopulate(IConfig startupConfig, string config) + private void ReadConfigAndPopulate() { - if (config == "Startup" && startupConfig != null) + // we are enabled by default + + IConfig startupConfig = m_gConfig.Configs["Startup"]; + + if(startupConfig == null) // should not happen + return; + + IConfig economyConfig = m_gConfig.Configs["Economy"]; + + // economymodule may be at startup or Economy (legacy) + string mmodule = startupConfig.GetString("economymodule",""); + if(String.IsNullOrEmpty(mmodule)) { - m_enabled = (startupConfig.GetString("economymodule", "BetaGridLikeMoneyModule") == "BetaGridLikeMoneyModule"); + if(economyConfig != null) + mmodule = economyConfig.GetString("economymodule",""); } - if (config == "Economy" && startupConfig != null) + if(!String.IsNullOrEmpty(mmodule) && mmodule != Name) { - PriceEnergyUnit = startupConfig.GetInt("PriceEnergyUnit", 100); - PriceObjectClaim = startupConfig.GetInt("PriceObjectClaim", 10); - PricePublicObjectDecay = startupConfig.GetInt("PricePublicObjectDecay", 4); - PricePublicObjectDelete = startupConfig.GetInt("PricePublicObjectDelete", 4); - PriceParcelClaim = startupConfig.GetInt("PriceParcelClaim", 1); - PriceParcelClaimFactor = startupConfig.GetFloat("PriceParcelClaimFactor", 1f); - PriceUpload = startupConfig.GetInt("PriceUpload", 0); - PriceRentLight = startupConfig.GetInt("PriceRentLight", 5); - TeleportMinPrice = startupConfig.GetInt("TeleportMinPrice", 2); - TeleportPriceExponent = startupConfig.GetFloat("TeleportPriceExponent", 2f); - EnergyEfficiency = startupConfig.GetFloat("EnergyEfficiency", 1); - PriceObjectRent = startupConfig.GetFloat("PriceObjectRent", 1); - PriceObjectScaleFactor = startupConfig.GetFloat("PriceObjectScaleFactor", 10); - PriceParcelRent = startupConfig.GetInt("PriceParcelRent", 1); - PriceGroupCreate = startupConfig.GetInt("PriceGroupCreate", -1); - m_sellEnabled = startupConfig.GetBoolean("SellEnabled", false); + // some other money module selected + m_enabled = false; + return; } + + if(economyConfig == null) + return; + + PriceEnergyUnit = economyConfig.GetInt("PriceEnergyUnit", 0); + PriceObjectClaim = economyConfig.GetInt("PriceObjectClaim", 0); + PricePublicObjectDecay = economyConfig.GetInt("PricePublicObjectDecay", 4); + PricePublicObjectDelete = economyConfig.GetInt("PricePublicObjectDelete", 0); + PriceParcelClaim = economyConfig.GetInt("PriceParcelClaim", 0); + PriceParcelClaimFactor = economyConfig.GetFloat("PriceParcelClaimFactor", 1f); + PriceUpload = economyConfig.GetInt("PriceUpload", 0); + PriceRentLight = economyConfig.GetInt("PriceRentLight", 0); + TeleportMinPrice = economyConfig.GetInt("TeleportMinPrice", 0); + TeleportPriceExponent = economyConfig.GetFloat("TeleportPriceExponent", 2f); + EnergyEfficiency = economyConfig.GetFloat("EnergyEfficiency", 1); + PriceObjectRent = economyConfig.GetFloat("PriceObjectRent", 0); + PriceObjectScaleFactor = economyConfig.GetFloat("PriceObjectScaleFactor", 10); + PriceParcelRent = economyConfig.GetInt("PriceParcelRent", 0); + PriceGroupCreate = economyConfig.GetInt("PriceGroupCreate", -1); + m_sellEnabled = economyConfig.GetBoolean("SellEnabled", true); } private void GetClientFunds(IClientAPI client) @@ -302,7 +313,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule private bool doMoneyTransfer(UUID Sender, UUID Receiver, int amount, int transactiontype, string description) { bool result = true; - + return result; } @@ -376,10 +387,10 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule else { m_log.ErrorFormat( - "[MONEY]: Could not resolve user {0}", + "[MONEY]: Could not resolve user {0}", agentID); } - + return String.Empty; } @@ -463,7 +474,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule Hashtable quoteResponse = new Hashtable(); XmlRpcResponse returnval = new XmlRpcResponse(); - + Hashtable currencyResponse = new Hashtable(); currencyResponse.Add("estimatedCost", 0); currencyResponse.Add("currencyBuy", amount); @@ -474,7 +485,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule returnval.Value = quoteResponse; return returnval; - + } @@ -484,7 +495,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule // Hashtable requestData = (Hashtable) request.Params[0]; // UUID agentId = UUID.Zero; // int amount = 0; - + XmlRpcResponse returnval = new XmlRpcResponse(); Hashtable returnresp = new Hashtable(); returnresp.Add("success", true); @@ -535,7 +546,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule // UUID agentId = UUID.Zero; // int amount = 0; - + retparam.Add("success", true); ret.Value = retparam; @@ -552,7 +563,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// private void CheckExistAndRefreshFunds(UUID agentID) { - + } /// @@ -562,14 +573,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// private int GetFundsForAgentID(UUID AgentID) { - int returnfunds = 82101; // Set it to the OpenSim version, plus the IG build number. Muahahaha; - + int returnfunds = 0; + return returnfunds; } // private void SetLocalFundsForAgentID(UUID AgentID, int amount) // { - + // } #endregion @@ -688,7 +699,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// public void ClientClosed(UUID AgentID, Scene scene) { - + } /// @@ -707,19 +718,19 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e) { - - + + lock (e) { e.economyValidated = true; } - - + + } private void processLandBuy(Object osender, EventManager.LandBuyArgs e) { - + } /// @@ -729,7 +740,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// private void MoneyTransferAction(Object osender, EventManager.MoneyTransferArgs e) { - + } /// @@ -738,7 +749,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// private void MakeChildAgent(ScenePresence avatar) { - + } /// @@ -747,7 +758,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// private void ClientLoggedOut(UUID AgentId, Scene scene) { - + } /// @@ -767,7 +778,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID) { - + //m_log.Info("[FRIEND]: " + avatar.Name + " status:" + (!avatar.IsChildAgent).ToString()); } @@ -808,12 +819,12 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule Scene s = LocateSceneClientIn(remoteClient.AgentId); - // Implmenting base sale data checking here so the default OpenSimulator implementation isn't useless + // Implmenting base sale data checking here so the default OpenSimulator implementation isn't useless // combined with other implementations. We're actually validating that the client is sending the data // that it should. In theory, the client should already know what to send here because it'll see it when it - // gets the object data. If the data sent by the client doesn't match the object, the viewer probably has an - // old idea of what the object properties are. Viewer developer Hazim informed us that the base module - // didn't check the client sent data against the object do any. Since the base modules are the + // gets the object data. If the data sent by the client doesn't match the object, the viewer probably has an + // old idea of what the object properties are. Viewer developer Hazim informed us that the base module + // didn't check the client sent data against the object do any. Since the base modules are the // 'crowning glory' examples of good practice.. // Validate that the object exists in the scene the user is in @@ -823,15 +834,15 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found.", false); return; } - - // Validate that the client sent the price that the object is being sold for + + // Validate that the client sent the price that the object is being sold for if (part.SalePrice != salePrice) { remoteClient.SendAgentAlertMessage("Cannot buy at this price. Buy Failed. If you continue to get this relog.", false); return; } - // Validate that the client sent the proper sale type the object has set + // Validate that the client sent the proper sale type the object has set if (part.ObjectSaleType != saleType) { remoteClient.SendAgentAlertMessage("Cannot buy this way. Buy Failed. If you continue to get this relog.", false); @@ -842,6 +853,15 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule if (module != null) module.BuyObject(remoteClient, categoryID, localID, saleType, salePrice); } + + public void MoveMoney(UUID fromUser, UUID toUser, int amount, string text) + { + } + + public bool MoveMoney(UUID fromUser, UUID toUser, int amount, MoneyTransactionType type, string text) + { + return true; + } } public enum TransactionType : int diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index fb644b7..bb23f2f 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -43,9 +43,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC public class NPCAvatar : IClientAPI, INPC { public bool SenseAsAgent { get; set; } + public UUID Owner + { + get { return m_ownerID;} + } public delegate void ChatToNPC( - string message, byte type, Vector3 fromPos, string fromName, + string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source, byte audible); /// @@ -61,9 +65,14 @@ namespace OpenSim.Region.OptionalModules.World.NPC private readonly string m_firstname; private readonly string m_lastname; private readonly Vector3 m_startPos; - private readonly UUID m_uuid; + private UUID m_uuid = UUID.Random(); private readonly Scene m_scene; private readonly UUID m_ownerID; + private UUID m_hostGroupID; + private string m_profileAbout = ""; + private UUID m_profileImage = UUID.Zero; + private string m_born; + public List SelectedObjects {get; private set;} public NPCAvatar( string firstname, string lastname, Vector3 position, UUID ownerID, bool senseAsAgent, Scene scene) @@ -75,6 +84,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC m_scene = scene; m_ownerID = ownerID; SenseAsAgent = senseAsAgent; + m_hostGroupID = UUID.Zero; } public NPCAvatar( @@ -87,6 +97,25 @@ namespace OpenSim.Region.OptionalModules.World.NPC m_scene = scene; m_ownerID = ownerID; SenseAsAgent = senseAsAgent; + m_hostGroupID = UUID.Zero; + } + + public string profileAbout + { + get { return m_profileAbout; } + set + { + if(value.Length > 255) + m_profileAbout = value.Substring(0,255); + else + m_profileAbout = value; + } + } + + public UUID profileImage + { + get { return m_profileImage; } + set { m_profileImage = value; } } public IScene Scene @@ -94,6 +123,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC get { return m_scene; } } + public int PingTimeMS { get { return 0; } } + public UUID OwnerID { get { return m_ownerID; } @@ -187,9 +218,15 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - - public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, Quaternion SitOrientation, bool autopilot, - Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) + + public void SendFindAgent(UUID HunterID, UUID PreyID, double GlobalX, double GlobalY) + { + + } + + public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, + Quaternion SitOrientation, bool autopilot, + Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) { } @@ -248,7 +285,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC #pragma warning disable 67 public event Action OnLogout; public event ObjectPermissions OnObjectPermissions; - + public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy; public event MoneyTransferRequest OnMoneyTransferRequest; public event ParcelBuy OnParcelBuy; public event Action OnConnectionClosed; @@ -268,6 +305,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event ObjectDrop OnObjectDrop; public event StartAnim OnStartAnim; public event StopAnim OnStopAnim; + public event ChangeAnim OnChangeAnim; public event LinkObjects OnLinkObjects; public event DelinkObjects OnDelinkObjects; public event RequestMapBlocks OnRequestMapBlocks; @@ -280,6 +318,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event SetAlwaysRun OnSetAlwaysRun; public event DeRezObject OnDeRezObject; + public event RezRestoreToWorld OnRezRestoreToWorld; public event Action OnRegionHandShakeReply; public event GenericCall1 OnRequestWearables; public event Action OnCompleteMovementToRegion; @@ -318,6 +357,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event UpdatePrimTexture OnUpdatePrimTexture; public event UpdateVector OnUpdatePrimGroupPosition; public event UpdateVector OnUpdatePrimSinglePosition; + public event ClientChangeObject onClientChangeObject; public event UpdatePrimRotation OnUpdatePrimGroupRotation; public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; @@ -456,7 +496,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event ClassifiedInfoRequest OnClassifiedInfoRequest; public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; public event ClassifiedDelete OnClassifiedDelete; - public event ClassifiedDelete OnClassifiedGodDelete; + public event ClassifiedGodDelete OnClassifiedGodDelete; public event EventNotificationAddRequest OnEventNotificationAddRequest; public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; @@ -479,7 +519,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event AvatarInterestUpdate OnAvatarInterestUpdate; public event PlacesQuery OnPlacesQuery; - + public event FindAgentUpdate OnFindAgent; public event TrackAgentUpdate OnTrackAgent; public event NewUserReport OnUserReport; @@ -495,11 +535,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; public event SimWideDeletesDelegate OnSimWideDeletes; public event SendPostcard OnSendPostcard; + public event ChangeInventoryItemFlags OnChangeInventoryItemFlags; public event MuteListEntryUpdate OnUpdateMuteListEntry; public event MuteListEntryRemove OnRemoveMuteListEntry; public event GodlikeMessage onGodlikeMessage; public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; - + public event GenericCall2 OnUpdateThrottles; #pragma warning restore 67 #endregion @@ -522,6 +563,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public virtual UUID AgentId { get { return m_uuid; } + set { m_uuid = value; } } public UUID SessionId @@ -562,24 +604,40 @@ namespace OpenSim.Region.OptionalModules.World.NPC } public UUID ActiveGroupId { - get { return UUID.Zero; } + get { return m_hostGroupID; } + set { m_hostGroupID = value; } } public string ActiveGroupName { get { return String.Empty; } + set { } } public ulong ActiveGroupPowers { get { return 0; } + set { } + } + + public string Born + { + get { return m_born; } + set { m_born = value; } } public bool IsGroupMember(UUID groupID) { - return false; + return (m_hostGroupID == groupID); + } + + public Dictionary GetGroupPowers() + { + return new Dictionary(); } + public void SetGroupPowers(Dictionary powers) { } + public ulong GetGroupPowers(UUID groupID) { return 0; @@ -627,6 +685,17 @@ namespace OpenSim.Region.OptionalModules.World.NPC public virtual void SetChildAgentThrottle(byte[] throttle) { } + + public virtual void SetChildAgentThrottle(byte[] throttle, float factor) + { + + } + + public void SetAgentThrottleSilent(int throttle, int setting) + { + + + } public byte[] GetThrottlesPacked(float multiplier) { return new byte[0]; @@ -665,6 +734,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC } + public virtual bool CanSendLayerData() + { + return false; + } + public virtual void SendLayerData(float[] map) { } @@ -676,9 +750,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public virtual void SendWindData(Vector2[] windSpeeds) { } + public virtual void SendWindData(int version, Vector2[] windSpeeds) { } - public virtual void SendCloudData(float[] cloudCover) { } + public virtual void SendCloudData(int version, float[] cloudCover) { } public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) { @@ -739,7 +813,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public void SendAvatarDataImmediate(ISceneEntity avatar) + public void SendEntityFullUpdateImmediate(ISceneEntity avatar) + { + } + + public void SendEntityTerseUpdateImmediate(ISceneEntity ent) { } @@ -772,6 +850,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } + public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId) + { + } + public virtual void SendRemoveInventoryItem(UUID itemID) { } @@ -788,7 +870,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public virtual void SendXferPacket(ulong xferID, uint packet, byte[] data) + public virtual void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory) { } public virtual void SendAbortXferPacket(ulong xferID) @@ -833,6 +915,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } + public void SendAlertMessage(string message, string info) + { + } + public void SendSystemAlertMessage(string message) { } @@ -849,7 +935,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC OnRegionHandShakeReply(this); } } - + public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) { } @@ -869,7 +955,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public void SendImageFirstPart(ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec) { } - + public void SendImageNotFound(UUID imageid) { } @@ -877,7 +963,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData) { } - + public void SendShutdownConnectionNotice() { } @@ -888,7 +974,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { - + } public void SendObjectPropertiesReply(ISceneEntity entity) @@ -902,12 +988,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC public void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks) { } - + public void SendViewerTime(int phase) { } - public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, + public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType, string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, UUID partnerID) { @@ -933,10 +1019,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC public void Close() { - Close(false); + Close(true, false); } - public void Close(bool force) + public void Close(bool sendStop, bool force) { // Remove ourselves from the scene m_scene.RemoveClient(AgentId, false); @@ -947,7 +1033,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC // We never start the client, so always fail. throw new NotImplementedException(); } - + public void Stop() { } @@ -1142,11 +1228,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC public void SendJoinGroupReply(UUID groupID, bool success) { } - + public void SendEjectGroupMemberReply(UUID agentID, UUID groupID, bool success) { } - + public void SendLeaveGroupReply(UUID groupID, bool success) { } @@ -1155,6 +1241,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } + public void SendAgentGroupDataUpdate(UUID avatarID, GroupMembershipData[] data) + { + } + public void SendTerminateFriend(UUID exFriendID) { } @@ -1208,10 +1298,26 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } + public void UpdateGroupMembership(GroupMembershipData[] data) + { + } + + public void GroupMembershipRemove(UUID GroupID) + { + } + + public void GroupMembershipAddReplace(UUID GroupID,ulong GroupPowers) + { + } + public void SendUseCachedMuteList() { } + public void SendEmpytMuteList() + { + } + public void SendMuteListUpdate(string filename) { } @@ -1220,7 +1326,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } #endregion - + public void SendRebakeAvatarTextures(UUID textureID) { } @@ -1228,15 +1334,15 @@ namespace OpenSim.Region.OptionalModules.World.NPC public void SendAvatarInterestsReply(UUID avatarID, uint wantMask, string wantText, uint skillsMask, string skillsText, string languages) { } - + public void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt) { } - + public void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier) { } - + public void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID,int amt) { } @@ -1256,7 +1362,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId) { } - + public void SendAgentTerseUpdate(ISceneEntity presence) { } @@ -1265,9 +1371,22 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } + public void SendSelectedPartsProprieties(List parts) + { + } + public void SendPartPhysicsProprieties(ISceneEntity entity) { } + public void SendPartFullUpdate(ISceneEntity ent, uint? parentID) + { + } + + public int GetAgentThrottleSilent(int throttle) + { + return 0; + } + } } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 3b94dff..ced82e6 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -52,6 +52,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC private Dictionary m_avatars = new Dictionary(); + + + private NPCOptionsFlags m_NPCOptionFlags; + public NPCOptionsFlags NPCOptionFlags {get {return m_NPCOptionFlags;}} + public bool Enabled { get; private set; } public void Initialise(IConfigSource source) @@ -59,6 +64,21 @@ namespace OpenSim.Region.OptionalModules.World.NPC IConfig config = source.Configs["NPC"]; Enabled = (config != null && config.GetBoolean("Enabled", false)); + m_NPCOptionFlags = NPCOptionsFlags.None; + if(Enabled) + { + if(config.GetBoolean("AllowNotOwned", true)) + m_NPCOptionFlags |= NPCOptionsFlags.AllowNotOwned; + + if(config.GetBoolean("AllowSenseAsAvatar", true)) + m_NPCOptionFlags |= NPCOptionsFlags.AllowSenseAsAvatar; + + if(config.GetBoolean("AllowCloneOtherAvatars", true)) + m_NPCOptionFlags |= NPCOptionsFlags.AllowCloneOtherAvatars; + + if(config.GetBoolean("NoNPCGroup", true)) + m_NPCOptionFlags |= NPCOptionsFlags.NoNPCGroup; + } } public void AddRegion(Scene scene) @@ -137,17 +157,18 @@ namespace OpenSim.Region.OptionalModules.World.NPC } public UUID CreateNPC(string firstname, string lastname, - Vector3 position, UUID owner, bool senseAsAgent, Scene scene, + Vector3 position, UUID owner, bool senseAsAgent, Scene scene, AvatarAppearance appearance) { - return CreateNPC(firstname, lastname, position, UUID.Zero, owner, senseAsAgent, scene, appearance); + return CreateNPC(firstname, lastname, position, UUID.Zero, owner, "", UUID.Zero, senseAsAgent, scene, appearance); } public UUID CreateNPC(string firstname, string lastname, - Vector3 position, UUID agentID, UUID owner, bool senseAsAgent, Scene scene, + Vector3 position, UUID agentID, UUID owner, string groupTitle, UUID groupID, bool senseAsAgent, Scene scene, AvatarAppearance appearance) { NPCAvatar npcAvatar = null; + string born = DateTime.UtcNow.ToString(); try { @@ -167,10 +188,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0, int.MaxValue); - m_log.DebugFormat( - "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}", - firstname, lastname, npcAvatar.AgentId, owner, - senseAsAgent, position, scene.RegionInfo.RegionName); +// m_log.DebugFormat( +// "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}", +// firstname, lastname, npcAvatar.AgentId, owner, senseAsAgent, position, scene.RegionInfo.RegionName); AgentCircuitData acd = new AgentCircuitData(); acd.AgentID = npcAvatar.AgentId; @@ -181,30 +201,44 @@ namespace OpenSim.Region.OptionalModules.World.NPC AvatarAppearance npcAppearance = new AvatarAppearance(appearance, true); acd.Appearance = npcAppearance; - lock (m_avatars) + /* + for (int i = 0; + i < acd.Appearance.Texture.FaceTextures.Length; i++) { - scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, - acd); - scene.AddNewAgent(npcAvatar, PresenceType.Npc); + m_log.DebugFormat( + "[NPC MODULE]: NPC avatar {0} has texture id {1} : {2}", + acd.AgentID, i, + acd.Appearance.Texture.FaceTextures[i]); + } + */ - ScenePresence sp; - if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) - { - sp.CompleteMovement(npcAvatar, false); - m_avatars.Add(npcAvatar.AgentId, npcAvatar); - m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", npcAvatar.AgentId, sp.Name); +// ManualResetEvent ev = new ManualResetEvent(false); - return npcAvatar.AgentId; - } - else +// Util.FireAndForget(delegate(object x) { + lock (m_avatars) { - m_log.WarnFormat( - "[NPC MODULE]: Could not find scene presence for NPC {0} {1}", - sp.Name, sp.UUID); + scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, acd); + scene.AddNewAgent(npcAvatar, PresenceType.Npc); - return UUID.Zero; + ScenePresence sp; + if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) + { + npcAvatar.Born = born; + npcAvatar.ActiveGroupId = groupID; + sp.CompleteMovement(npcAvatar, false); + sp.Grouptitle = groupTitle; + m_avatars.Add(npcAvatar.AgentId, npcAvatar); +// m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", npcAvatar.AgentId, sp.Name); + } } - } +// ev.Set(); +// }); + +// ev.WaitOne(); + +// m_log.DebugFormat("[NPC MODULE]: Created NPC with id {0}", npcAvatar.AgentId); + + return npcAvatar.AgentId; } public bool MoveToTarget(UUID agentID, Scene scene, Vector3 pos, @@ -220,6 +254,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC if (sp.IsSatOnObject || sp.SitGround) return false; +// m_log.DebugFormat( +// "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", +// sp.Name, pos, scene.RegionInfo.RegionName, +// noFly, landAtTarget); + sp.MoveToTarget(pos, noFly, landAtTarget); sp.SetAlwaysRun = running; @@ -382,6 +421,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC { if (m_avatars.TryGetValue(agentID, out av)) { + /* + m_log.DebugFormat("[NPC MODULE]: Found {0} {1} to remove", + agentID, av.Name); + */ doRemove = true; } } @@ -410,9 +453,15 @@ namespace OpenSim.Region.OptionalModules.World.NPC { NPCAvatar av; if (m_avatars.TryGetValue(npcID, out av)) + { + if (npcID == callerID) + return true; return CheckPermissions(av, callerID); + } else + { return false; + } } } diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 77dfd40..9a1ea73 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -112,7 +112,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests // ScenePresence.SendInitialData() to reset our entire appearance. m_scene.AssetService.Store(AssetHelpers.CreateNotecardAsset(originalFace8TextureId)); - m_afMod.SetAppearance(sp, originalTe, null, null); + m_afMod.SetAppearance(sp, originalTe, null, new WearableCacheItem[0] ); UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance); @@ -209,10 +209,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests UserAccountHelpers.CreateUserWithInventory(m_scene, userId); ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); - InventoryItemBase att1Item + InventoryItemBase att1Item = UserInventoryHelpers.CreateInventoryItem( m_scene, "att1", TestHelpers.ParseTail(0x2), TestHelpers.ParseTail(0x3), sp.UUID, InventoryType.Object); - InventoryItemBase att2Item + InventoryItemBase att2Item = UserInventoryHelpers.CreateInventoryItem( m_scene, "att2", TestHelpers.ParseTail(0x12), TestHelpers.ParseTail(0x13), sp.UUID, InventoryType.Object); @@ -483,4 +483,4 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests Assert.That(npc.ParentID, Is.EqualTo(0)); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs index 0927c4f..7e3bd7f 100644 --- a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs +++ b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs @@ -54,38 +54,38 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments private Scene m_scene; public string Name { get { return "Scene Commands Module"; } } - + public Type ReplaceableInterface { get { return null; } } - + public void Initialise(IConfigSource source) { // m_log.DebugFormat("[SCENE COMMANDS MODULE]: INITIALIZED MODULE"); } - + public void PostInitialise() { // m_log.DebugFormat("[SCENE COMMANDS MODULE]: POST INITIALIZED MODULE"); } - + public void Close() { // m_log.DebugFormat("[SCENE COMMANDS MODULE]: CLOSED MODULE"); } - + public void AddRegion(Scene scene) { // m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); m_scene = scene; - + m_scene.RegisterModuleInterface(this); } - + public void RemoveRegion(Scene scene) { // m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); - } - + } + public void RegionLoaded(Scene scene) { // m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); @@ -96,19 +96,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments "List current scene options.", "active - if false then main scene update and maintenance loops are suspended.\n" + "animations - if true then extra animations debug information is logged.\n" - + "appear-refresh - if true then appearance is resent to other avatars every 60 seconds.\n" - + "child-repri - how far an avatar must move in meters before we update the position of its child agents in neighbouring regions.\n" - + "client-pos-upd - the tolerance before clients are updated with new rotation information for an avatar.\n" - + "client-rot-upd - the tolerance before clients are updated with new rotation information for an avatar.\n" - + "client-vel-upd - the tolerance before clients are updated with new velocity information for an avatar.\n" - + "root-upd-per - if greater than 1, terse updates are only sent to root agents other than the originator on every n updates.\n" - + "child-upd-per - if greater than 1, terse updates are only sent to child agents on every n updates.\n" + "collisions - if false then collisions with other objects are turned off.\n" + "pbackup - if false then periodic scene backup is turned off.\n" + "physics - if false then all physics objects are non-physical.\n" + "scripting - if false then no scripting operations happen.\n" + "teleport - if true then some extra teleport debug information is logged.\n" - + "update-on-timer - If true then the scene is updated via a timer. If false then a thread with sleep is used.\n" + "updates - if true then any frame which exceeds double the maximum desired frame time is logged.", HandleDebugSceneGetCommand); @@ -118,19 +110,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments "Turn on scene debugging options.", "active - if false then main scene update and maintenance loops are suspended.\n" + "animations - if true then extra animations debug information is logged.\n" - + "appear-refresh - if true then appearance is resent to other avatars every 60 seconds.\n" - + "child-repri - how far an avatar must move in meters before we update the position of its child agents in neighbouring regions.\n" - + "client-pos-upd - the tolerance before clients are updated with new rotation information for an avatar.\n" - + "client-rot-upd - the tolerance before clients are updated with new rotation information for an avatar.\n" - + "client-vel-upd - the tolerance before clients are updated with new velocity information for an avatar.\n" - + "root-upd-per - if greater than 1, terse updates are only sent to root agents other than the originator on every n updates.\n" - + "child-upd-per - if greater than 1, terse updates are only sent to child agents on every n updates.\n" + "collisions - if false then collisions with other objects are turned off.\n" + "pbackup - if false then periodic scene backup is turned off.\n" + "physics - if false then all physics objects are non-physical.\n" + "scripting - if false then no scripting operations happen.\n" + "teleport - if true then some extra teleport debug information is logged.\n" - + "update-on-timer - If true then the scene is updated via a timer. If false then a thread with sleep is used.\n" + "updates - if true then any frame which exceeds double the maximum desired frame time is logged.", HandleDebugSceneSetCommand); } @@ -155,18 +139,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments ConsoleDisplayList cdl = new ConsoleDisplayList(); cdl.AddRow("active", m_scene.Active); cdl.AddRow("animations", m_scene.DebugAnimations); - cdl.AddRow("appear-refresh", m_scene.SendPeriodicAppearanceUpdates); - cdl.AddRow("child-repri", m_scene.ChildReprioritizationDistance); - cdl.AddRow("client-pos-upd", m_scene.RootPositionUpdateTolerance); - cdl.AddRow("client-rot-upd", m_scene.RootRotationUpdateTolerance); - cdl.AddRow("client-vel-upd", m_scene.RootVelocityUpdateTolerance); - cdl.AddRow("root-upd-per", m_scene.RootTerseUpdatePeriod); - cdl.AddRow("child-upd-per", m_scene.ChildTerseUpdatePeriod); cdl.AddRow("pbackup", m_scene.PeriodicBackup); cdl.AddRow("physics", m_scene.PhysicsEnabled); cdl.AddRow("scripting", m_scene.ScriptsEnabled); cdl.AddRow("teleport", m_scene.DebugTeleporting); - cdl.AddRow("update-on-timer", m_scene.UpdateOnTimer); cdl.AddRow("updates", m_scene.DebugUpdates); MainConsole.Instance.OutputFormat("Scene {0} options:", m_scene.Name); @@ -210,69 +186,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments m_scene.DebugAnimations = active; } - if (options.ContainsKey("appear-refresh")) - { - bool newValue; - - // FIXME: This can only come from the console at the moment but might not always be true. - if (ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, options["appear-refresh"], out newValue)) - m_scene.SendPeriodicAppearanceUpdates = newValue; - } - - if (options.ContainsKey("child-repri")) - { - double newValue; - - // FIXME: This can only come from the console at the moment but might not always be true. - if (ConsoleUtil.TryParseConsoleDouble(MainConsole.Instance, options["child-repri"], out newValue)) - m_scene.ChildReprioritizationDistance = newValue; - } - - if (options.ContainsKey("client-pos-upd")) - { - float newValue; - - // FIXME: This can only come from the console at the moment but might not always be true. - if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-pos-upd"], out newValue)) - m_scene.RootPositionUpdateTolerance = newValue; - } - - if (options.ContainsKey("client-rot-upd")) - { - float newValue; - - // FIXME: This can only come from the console at the moment but might not always be true. - if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-rot-upd"], out newValue)) - m_scene.RootRotationUpdateTolerance = newValue; - } - - if (options.ContainsKey("client-vel-upd")) - { - float newValue; - - // FIXME: This can only come from the console at the moment but might not always be true. - if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-vel-upd"], out newValue)) - m_scene.RootVelocityUpdateTolerance = newValue; - } - - if (options.ContainsKey("root-upd-per")) - { - int newValue; - - // FIXME: This can only come from the console at the moment but might not always be true. - if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, options["root-upd-per"], out newValue)) - m_scene.RootTerseUpdatePeriod = newValue; - } - - if (options.ContainsKey("child-upd-per")) - { - int newValue; - - // FIXME: This can only come from the console at the moment but might not always be true. - if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, options["child-upd-per"], out newValue)) - m_scene.ChildTerseUpdatePeriod = newValue; - } - if (options.ContainsKey("pbackup")) { bool active; @@ -308,21 +221,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments m_scene.DebugTeleporting = enableTeleportDebugging; } - if (options.ContainsKey("update-on-timer")) - { - bool enableUpdateOnTimer; - if (bool.TryParse(options["update-on-timer"], out enableUpdateOnTimer)) - { - m_scene.UpdateOnTimer = enableUpdateOnTimer; - m_scene.Active = false; - - while (m_scene.IsRunning) - Thread.Sleep(20); - - m_scene.Active = true; - } - } - if (options.ContainsKey("updates")) { bool enableUpdateDebugging; @@ -334,4 +232,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments } } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs index e4a3382..6e1f8bb 100644 --- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs +++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs @@ -27,8 +27,13 @@ using System; using System.Collections.Generic; +using System.IO; using System.Reflection; using System.Timers; +using System.Threading; +using System.Xml; +using System.Xml.Serialization; + using OpenMetaverse; using log4net; using Mono.Addins; @@ -38,17 +43,15 @@ using OpenSim.Region.CoreModules.Framework.InterfaceCommander; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; -using System.Xml; -using System.Xml.Serialization; -using System.IO; +using Timer= System.Timers.Timer; namespace OpenSim.Region.OptionalModules.World.TreePopulator { /// - /// Version 2.02 - Still hacky + /// Version 2.02 - Still hacky /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "TreePopulatorModule")] - public class TreePopulatorModule : INonSharedRegionModule, ICommandableModule, IVegetationModule + public class TreePopulatorModule : INonSharedRegionModule, ICommandableModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private readonly Commander m_commander = new Commander("tree"); @@ -60,7 +63,7 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator public string m_name; public Boolean m_frozen; public Tree m_tree_type; - public int m_tree_quantity; + public int m_tree_quantity; public float m_treeline_low; public float m_treeline_high; public Vector3 m_seed_point; @@ -78,24 +81,24 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator { } - public Copse(string fileName, Boolean planted) + public Copse(string fileName, Boolean planted) { Copse cp = (Copse)DeserializeObject(fileName); - this.m_name = cp.m_name; - this.m_frozen = cp.m_frozen; - this.m_tree_quantity = cp.m_tree_quantity; - this.m_treeline_high = cp.m_treeline_high; - this.m_treeline_low = cp.m_treeline_low; - this.m_range = cp.m_range; - this.m_tree_type = cp.m_tree_type; - this.m_seed_point = cp.m_seed_point; - this.m_initial_scale = cp.m_initial_scale; - this.m_maximum_scale = cp.m_maximum_scale; - this.m_initial_scale = cp.m_initial_scale; - this.m_rate = cp.m_rate; - this.m_planted = planted; - this.m_trees = new List(); + m_name = cp.m_name; + m_frozen = cp.m_frozen; + m_tree_quantity = cp.m_tree_quantity; + m_treeline_high = cp.m_treeline_high; + m_treeline_low = cp.m_treeline_low; + m_range = cp.m_range; + m_tree_type = cp.m_tree_type; + m_seed_point = cp.m_seed_point; + m_initial_scale = cp.m_initial_scale; + m_maximum_scale = cp.m_maximum_scale; + m_initial_scale = cp.m_initial_scale; + m_rate = cp.m_rate; + m_planted = planted; + m_trees = new List(); } public Copse(string copsedef) @@ -103,61 +106,63 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator char[] delimiterChars = {':', ';'}; string[] field = copsedef.Split(delimiterChars); - this.m_name = field[1].Trim(); - this.m_frozen = (copsedef[0] == 'F'); - this.m_tree_quantity = int.Parse(field[2]); - this.m_treeline_high = float.Parse(field[3], Culture.NumberFormatInfo); - this.m_treeline_low = float.Parse(field[4], Culture.NumberFormatInfo); - this.m_range = double.Parse(field[5], Culture.NumberFormatInfo); - this.m_tree_type = (Tree) Enum.Parse(typeof(Tree),field[6]); - this.m_seed_point = Vector3.Parse(field[7]); - this.m_initial_scale = Vector3.Parse(field[8]); - this.m_maximum_scale = Vector3.Parse(field[9]); - this.m_rate = Vector3.Parse(field[10]); - this.m_planted = true; - this.m_trees = new List(); + m_name = field[1].Trim(); + m_frozen = (copsedef[0] == 'F'); + m_tree_quantity = int.Parse(field[2]); + m_treeline_high = float.Parse(field[3], Culture.NumberFormatInfo); + m_treeline_low = float.Parse(field[4], Culture.NumberFormatInfo); + m_range = double.Parse(field[5], Culture.NumberFormatInfo); + m_tree_type = (Tree) Enum.Parse(typeof(Tree),field[6]); + m_seed_point = Vector3.Parse(field[7]); + m_initial_scale = Vector3.Parse(field[8]); + m_maximum_scale = Vector3.Parse(field[9]); + m_rate = Vector3.Parse(field[10]); + m_planted = true; + m_trees = new List(); } public Copse(string name, int quantity, float high, float low, double range, Vector3 point, Tree type, Vector3 scale, Vector3 max_scale, Vector3 rate, List trees) { - this.m_name = name; - this.m_frozen = false; - this.m_tree_quantity = quantity; - this.m_treeline_high = high; - this.m_treeline_low = low; - this.m_range = range; - this.m_tree_type = type; - this.m_seed_point = point; - this.m_initial_scale = scale; - this.m_maximum_scale = max_scale; - this.m_rate = rate; - this.m_planted = false; - this.m_trees = trees; + m_name = name; + m_frozen = false; + m_tree_quantity = quantity; + m_treeline_high = high; + m_treeline_low = low; + m_range = range; + m_tree_type = type; + m_seed_point = point; + m_initial_scale = scale; + m_maximum_scale = max_scale; + m_rate = rate; + m_planted = false; + m_trees = trees; } public override string ToString() { - string frozen = (this.m_frozen ? "F" : "A"); + string frozen = (m_frozen ? "F" : "A"); - return string.Format("{0}TPM: {1}; {2}; {3:0.0}; {4:0.0}; {5:0.0}; {6}; {7:0.0}; {8:0.0}; {9:0.0}; {10:0.00};", + return string.Format("{0}TPM: {1}; {2}; {3:0.0}; {4:0.0}; {5:0.0}; {6}; {7:0.0}; {8:0.0}; {9:0.0}; {10:0.00};", frozen, - this.m_name, - this.m_tree_quantity, - this.m_treeline_high, - this.m_treeline_low, - this.m_range, - this.m_tree_type, - this.m_seed_point.ToString(), - this.m_initial_scale.ToString(), - this.m_maximum_scale.ToString(), - this.m_rate.ToString()); + m_name, + m_tree_quantity, + m_treeline_high, + m_treeline_low, + m_range, + m_tree_type, + m_seed_point.ToString(), + m_initial_scale.ToString(), + m_maximum_scale.ToString(), + m_rate.ToString()); } } - private List m_copse; - - private double m_update_ms = 1000.0; // msec between updates + private List m_copses = new List(); + private object mylock; + private double m_update_ms = 1000.0; // msec between updates private bool m_active_trees = false; + private bool m_enabled = true; // original default + private bool m_allowGrow = true; // original default Timer CalculateTrees; @@ -174,51 +179,51 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator public void Initialise(IConfigSource config) { - - // ini file settings - try + IConfig moduleConfig = config.Configs["Trees"]; + if (moduleConfig != null) { - m_active_trees = config.Configs["Trees"].GetBoolean("active_trees", m_active_trees); - } - catch (Exception) - { - m_log.Debug("[TREES]: ini failure for active_trees - using default"); + m_enabled = moduleConfig.GetBoolean("enabled", m_enabled); + m_active_trees = moduleConfig.GetBoolean("active_trees", m_active_trees); + m_allowGrow = moduleConfig.GetBoolean("allowGrow", m_allowGrow); + m_update_ms = moduleConfig.GetDouble("update_rate", m_update_ms); } - try - { - m_update_ms = config.Configs["Trees"].GetDouble("update_rate", m_update_ms); - } - catch (Exception) - { - m_log.Debug("[TREES]: ini failure for update_rate - using default"); - } + if(!m_enabled) + return; + + m_copses = new List(); + mylock = new object(); InstallCommands(); - m_log.Debug("[TREES]: Initialised tree module"); + m_log.Debug("[TREES]: Initialised tree populator module"); } public void AddRegion(Scene scene) { + if(!m_enabled) + return; m_scene = scene; m_scene.RegisterModuleCommander(m_commander); m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; - + m_scene.EventManager.OnPrimsLoaded += EventManager_OnPrimsLoaded; } public void RemoveRegion(Scene scene) { - } + if(!m_enabled) + return; + if(m_active_trees && CalculateTrees != null) + { + CalculateTrees.Dispose(); + CalculateTrees = null; + } + m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole; + m_scene.EventManager.OnPrimsLoaded -= EventManager_OnPrimsLoaded; + } public void RegionLoaded(Scene scene) { - ReloadCopse(); - if (m_copse.Count > 0) - m_log.Info("[TREES]: Copse load complete"); - - if (m_active_trees) - activeizeTreeze(true); } public void Close() @@ -240,6 +245,16 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator //-------------------------------------------------------------- + private void EventManager_OnPrimsLoaded(Scene s) + { + ReloadCopse(); + if (m_copses.Count > 0) + m_log.Info("[TREES]: Copses loaded" ); + + if (m_active_trees) + activeizeTreeze(true); + } + #region ICommandableModule Members private void HandleTreeActive(Object[] args) @@ -267,25 +282,57 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator string copsename = ((string)args[0]).Trim(); Boolean freezeState = (Boolean) args[1]; - foreach (Copse cp in m_copse) + lock(mylock) { - if (cp.m_name == copsename && (!cp.m_frozen && freezeState || cp.m_frozen && !freezeState)) + foreach (Copse cp in m_copses) { - cp.m_frozen = freezeState; - foreach (UUID tree in cp.m_trees) + if (cp.m_name != copsename) + continue; + + if(!cp.m_frozen && freezeState || cp.m_frozen && !freezeState) { - SceneObjectPart sop = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; - sop.Name = (freezeState ? sop.Name.Replace("ATPM", "FTPM") : sop.Name.Replace("FTPM", "ATPM")); - sop.ParentGroup.HasGroupChanged = true; - } + cp.m_frozen = freezeState; + List losttrees = new List(); + foreach (UUID tree in cp.m_trees) + { + SceneObjectGroup sog = m_scene.GetSceneObjectGroup(tree); + if(sog != null && !sog.IsDeleted) + { + SceneObjectPart sop = sog.RootPart; + string name = sop.Name; + if(freezeState) + { + if(name.StartsWith("FTPM")) + continue; + if(!name.StartsWith("ATPM")) + continue; + sop.Name = sop.Name.Replace("ATPM", "FTPM"); + } + else + { + if(name.StartsWith("ATPM")) + continue; + if(!name.StartsWith("FTPM")) + continue; + sop.Name = sop.Name.Replace("FTPM", "ATPM"); + } + sop.ParentGroup.HasGroupChanged = true; + sog.ScheduleGroupForFullUpdate(); + } + else + losttrees.Add(tree); + } + foreach (UUID tree in losttrees) + cp.m_trees.Remove(tree); - m_log.InfoFormat("[TREES]: Activity for copse {0} is frozen {1}", copsename, freezeState); - return; - } - else if (cp.m_name == copsename && (cp.m_frozen && freezeState || !cp.m_frozen && !freezeState)) - { - m_log.InfoFormat("[TREES]: Copse {0} is already in the requested freeze state", copsename); - return; + m_log.InfoFormat("[TREES]: Activity for copse {0} is frozen {1}", copsename, freezeState); + return; + } + else + { + m_log.InfoFormat("[TREES]: Copse {0} is already in the requested freeze state", copsename); + return; + } } } m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename); @@ -297,17 +344,21 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator m_log.InfoFormat("[TREES]: Loading copse definition...."); - copse = new Copse(((string)args[0]), false); - foreach (Copse cp in m_copse) + lock(mylock) { - if (cp.m_name == copse.m_name) + copse = new Copse(((string)args[0]), false); { - m_log.InfoFormat("[TREES]: Copse: {0} is already defined - command failed", copse.m_name); - return; + foreach (Copse cp in m_copses) + { + if (cp.m_name == copse.m_name) + { + m_log.InfoFormat("[TREES]: Copse: {0} is already defined - command failed", copse.m_name); + return; + } + } } + m_copses.Add(copse); } - - m_copse.Add(copse); m_log.InfoFormat("[TREES]: Loaded copse: {0}", copse.ToString()); } @@ -318,20 +369,24 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator m_log.InfoFormat("[TREES]: New tree planting for copse {0}", copsename); UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; - foreach (Copse copse in m_copse) + lock(mylock) { - if (copse.m_name == copsename) + foreach (Copse copse in m_copses) { - if (!copse.m_planted) - { - // The first tree for a copse is created here - CreateTree(uuid, copse, copse.m_seed_point); - copse.m_planted = true; - return; - } - else + if (copse.m_name == copsename) { - m_log.InfoFormat("[TREES]: Copse {0} has already been planted", copsename); + if (!copse.m_planted) + { + // The first tree for a copse is created here + CreateTree(uuid, copse, copse.m_seed_point, true); + copse.m_planted = true; + return; + } + else + { + m_log.InfoFormat("[TREES]: Copse {0} has already been planted", copsename); + return; + } } } } @@ -376,45 +431,49 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator string copsename = ((string)args[0]).Trim(); Copse copseIdentity = null; - foreach (Copse cp in m_copse) + lock(mylock) { - if (cp.m_name == copsename) + foreach (Copse cp in m_copses) { - copseIdentity = cp; + if (cp.m_name == copsename) + { + copseIdentity = cp; + } } - } - if (copseIdentity != null) - { - foreach (UUID tree in copseIdentity.m_trees) + if (copseIdentity != null) { - if (m_scene.Entities.ContainsKey(tree)) - { - SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; - // Delete tree and alert clients (not silent) - m_scene.DeleteSceneObject(selectedTree.ParentGroup, false); - } - else + foreach (UUID tree in copseIdentity.m_trees) { - m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); + if (m_scene.Entities.ContainsKey(tree)) + { + SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; + // Delete tree and alert clients (not silent) + m_scene.DeleteSceneObject(selectedTree.ParentGroup, false); + } + else + { + m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); + } } + copseIdentity.m_trees = null; + m_copses.Remove(copseIdentity); + m_log.InfoFormat("[TREES]: Copse {0} has been removed", copsename); + } + else + { + m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename); } - copseIdentity.m_trees = new List(); - m_copse.Remove(copseIdentity); - m_log.InfoFormat("[TREES]: Copse {0} has been removed", copsename); - } - else - { - m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename); } } private void HandleTreeStatistics(Object[] args) { - m_log.InfoFormat("[TREES]: Activity State: {0}; Update Rate: {1}", m_active_trees, m_update_ms); - foreach (Copse cp in m_copse) + m_log.InfoFormat("[TREES]: region {0}:", m_scene.Name); + m_log.InfoFormat("[TREES]: Activity State: {0}; Update Rate: {1}", m_active_trees, m_update_ms); + foreach (Copse cp in m_copses) { - m_log.InfoFormat("[TREES]: Copse {0}; {1} trees; frozen {2}", cp.m_name, cp.m_trees.Count, cp.m_frozen); + m_log.InfoFormat("[TREES]: Copse {0}; {1} trees; frozen {2}", cp.m_name, cp.m_trees.Count, cp.m_frozen); } } @@ -442,7 +501,7 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator treeRateCommand.AddArgument("updateRate", "The required update rate (minimum 1000.0)", "Double"); Command treeReloadCommand = - new Command("reload", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeReload, "Reload copse definitions from the in-scene trees"); + new Command("reload", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeReload, "Reload copses from the in-scene trees"); Command treeRemoveCommand = new Command("remove", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeRemove, "Remove a copse definition and all its in-scene trees"); @@ -499,34 +558,17 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator treeShape.Scale = scale; treeShape.State = (byte)treeType; - return m_scene.AddNewPrim(uuid, groupID, position, rotation, treeShape); - } - - #endregion - - #region IEntityCreator Members - - protected static readonly PCode[] creationCapabilities = new PCode[] { PCode.NewTree, PCode.Tree }; - public PCode[] CreationCapabilities { get { return creationCapabilities; } } - - public SceneObjectGroup CreateEntity( - UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) - { - if (Array.IndexOf(creationCapabilities, (PCode)shape.PCode) < 0) - { - m_log.DebugFormat("[VEGETATION]: PCode {0} not handled by {1}", shape.PCode, Name); - return null; - } - - SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape); - SceneObjectPart rootPart = sceneObject.GetPart(sceneObject.UUID); + SceneObjectGroup sog = new SceneObjectGroup(uuid, position, rotation, treeShape); + SceneObjectPart rootPart = sog.RootPart; rootPart.AddFlag(PrimFlags.Phantom); - m_scene.AddNewSceneObject(sceneObject, true); - sceneObject.SetGroup(groupID, null); - - return sceneObject; + sog.SetGroup(groupID, null); + m_scene.AddNewSceneObject(sog, true, false); + sog.IsSelected = false; + rootPart.IsSelected = false; + sog.InvalidateEffectivePerms(); + return sog; } #endregion @@ -569,26 +611,27 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator private void ReloadCopse() { - m_copse = new List(); + m_copses = new List(); - EntityBase[] objs = m_scene.GetEntities(); - foreach (EntityBase obj in objs) + List grps = m_scene.GetSceneObjectGroups(); + foreach (SceneObjectGroup grp in grps) { - if (obj is SceneObjectGroup) - { - SceneObjectGroup grp = (SceneObjectGroup)obj; + if(grp.RootPart.Shape.PCode != (byte)PCode.NewTree && grp.RootPart.Shape.PCode != (byte)PCode.Tree) + continue; - if (grp.Name.Length > 5 && (grp.Name.Substring(0, 5) == "ATPM:" || grp.Name.Substring(0, 5) == "FTPM:")) + if (grp.Name.Length > 5 && (grp.Name.Substring(0, 5) == "ATPM:" || grp.Name.Substring(0, 5) == "FTPM:")) + { + // Create a new copse definition or add uuid to an existing definition + try { - // Create a new copse definition or add uuid to an existing definition - try - { - Boolean copsefound = false; - Copse copse = new Copse(grp.Name); + Boolean copsefound = false; + Copse grpcopse = new Copse(grp.Name); - foreach (Copse cp in m_copse) + lock(mylock) + { + foreach (Copse cp in m_copses) { - if (cp.m_name == copse.m_name) + if (cp.m_name == grpcopse.m_name) { copsefound = true; cp.m_trees.Add(grp.UUID); @@ -598,15 +641,15 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator if (!copsefound) { - m_log.InfoFormat("[TREES]: Found copse {0}", grp.Name); - m_copse.Add(copse); - copse.m_trees.Add(grp.UUID); + m_log.InfoFormat("[TREES]: adding copse {0}", grpcopse.m_name); + grpcopse.m_trees.Add(grp.UUID); + m_copses.Add(grpcopse); } } - catch - { - m_log.InfoFormat("[TREES]: Ill formed copse definition {0} - ignoring", grp.Name); - } + } + catch + { + m_log.InfoFormat("[TREES]: Ill formed copse definition {0} - ignoring", grp.Name); } } } @@ -617,166 +660,265 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator { if (activeYN) { - CalculateTrees = new Timer(m_update_ms); + if(CalculateTrees == null) + CalculateTrees = new Timer(m_update_ms); CalculateTrees.Elapsed += CalculateTrees_Elapsed; + CalculateTrees.AutoReset = false; CalculateTrees.Start(); } - else + else { CalculateTrees.Stop(); } - } + } private void growTrees() { - foreach (Copse copse in m_copse) + if(!m_allowGrow) + return; + + foreach (Copse copse in m_copses) { - if (!copse.m_frozen) + if (copse.m_frozen) + continue; + + if(copse.m_trees.Count == 0) + continue; + + float maxscale = copse.m_maximum_scale.Z; + float ratescale = 1.0f; + List losttrees = new List(); + foreach (UUID tree in copse.m_trees) { - foreach (UUID tree in copse.m_trees) - { - if (m_scene.Entities.ContainsKey(tree)) - { - SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; + SceneObjectGroup sog = m_scene.GetSceneObjectGroup(tree); - if (s_tree.Scale.X < copse.m_maximum_scale.X && s_tree.Scale.Y < copse.m_maximum_scale.Y && s_tree.Scale.Z < copse.m_maximum_scale.Z) - { - s_tree.Scale += copse.m_rate; - s_tree.ParentGroup.HasGroupChanged = true; - s_tree.ScheduleFullUpdate(); - } - } - else + if (sog != null && !sog.IsDeleted) + { + SceneObjectPart s_tree = sog.RootPart; + if (s_tree.Scale.Z < maxscale) { - m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); + ratescale = (float)Util.RandomClass.NextDouble(); + if(ratescale < 0.2f) + ratescale = 0.2f; + s_tree.Scale += copse.m_rate * ratescale; + sog.HasGroupChanged = true; + s_tree.ScheduleFullUpdate(); } } + else + losttrees.Add(tree); } + + foreach (UUID tree in losttrees) + copse.m_trees.Remove(tree); } } private void seedTrees() { - foreach (Copse copse in m_copse) + foreach (Copse copse in m_copses) { - if (!copse.m_frozen) + if (copse.m_frozen) + continue; + + if(copse.m_trees.Count == 0) + return; + + bool low = copse.m_trees.Count < (int)(copse.m_tree_quantity * 0.8f); + + if (!low && Util.RandomClass.NextDouble() < 0.75) + return; + + int maxbirths = (int)(copse.m_tree_quantity) - copse.m_trees.Count; + if(maxbirths <= 1) + return; + + if(maxbirths > 20) + maxbirths = 20; + + float minscale = 0; + if(!low && m_allowGrow) + minscale = copse.m_maximum_scale.Z * 0.75f;; + + int i = 0; + UUID[] current = copse.m_trees.ToArray(); + while(--maxbirths > 0) { - foreach (UUID tree in copse.m_trees) + if(current.Length > 1) + i = Util.RandomClass.Next(current.Length -1); + + UUID tree = current[i]; + SceneObjectGroup sog = m_scene.GetSceneObjectGroup(tree); + + if (sog != null && !sog.IsDeleted) { - if (m_scene.Entities.ContainsKey(tree)) - { - SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; + SceneObjectPart s_tree = sog.RootPart; - if (copse.m_trees.Count < copse.m_tree_quantity) - { - // Tree has grown enough to seed if it has grown by at least 25% of seeded to full grown height - if (s_tree.Scale.Z > copse.m_initial_scale.Z + (copse.m_maximum_scale.Z - copse.m_initial_scale.Z) / 4.0) - { - if (Util.RandomClass.NextDouble() > 0.75) - { - SpawnChild(copse, s_tree); - } - } - } - } - else - { - m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); - } + // Tree has grown enough to seed if it has grown by at least 25% of seeded to full grown height + if (s_tree.Scale.Z > minscale) + SpawnChild(copse, s_tree, true); } - } + else if(copse.m_trees.Contains(tree)) + copse.m_trees.Remove(tree); + } } } private void killTrees() { - foreach (Copse copse in m_copse) + foreach (Copse copse in m_copses) { - if (!copse.m_frozen && copse.m_trees.Count >= copse.m_tree_quantity) - { - foreach (UUID tree in copse.m_trees) - { - double killLikelyhood = 0.0; + if (copse.m_frozen) + continue; - if (m_scene.Entities.ContainsKey(tree)) - { - SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; - double selectedTreeScale = Math.Sqrt(Math.Pow(selectedTree.Scale.X, 2) + - Math.Pow(selectedTree.Scale.Y, 2) + - Math.Pow(selectedTree.Scale.Z, 2)); - - foreach (UUID picktree in copse.m_trees) - { - if (picktree != tree) - { - SceneObjectPart pickedTree = ((SceneObjectGroup)m_scene.Entities[picktree]).RootPart; - - double pickedTreeScale = Math.Sqrt(Math.Pow(pickedTree.Scale.X, 2) + - Math.Pow(pickedTree.Scale.Y, 2) + - Math.Pow(pickedTree.Scale.Z, 2)); + if (Util.RandomClass.NextDouble() < 0.25) + return; - double pickedTreeDistance = Vector3.Distance(pickedTree.AbsolutePosition, selectedTree.AbsolutePosition); + int maxbdeaths = copse.m_trees.Count - (int)(copse.m_tree_quantity * .98f) ; + if(maxbdeaths < 1) + return; - killLikelyhood += (selectedTreeScale / (pickedTreeScale * pickedTreeDistance)) * 0.1; - } - } + float odds; + float scale = 1.0f / copse.m_maximum_scale.Z; - if (Util.RandomClass.NextDouble() < killLikelyhood) - { - // Delete tree and alert clients (not silent) - m_scene.DeleteSceneObject(selectedTree.ParentGroup, false); - copse.m_trees.Remove(selectedTree.ParentGroup.UUID); - break; - } + int ntries = maxbdeaths * 4; + while(ntries-- > 0 ) + { + int next = 0; + if (copse.m_trees.Count > 1) + next = Util.RandomClass.Next(copse.m_trees.Count - 1); + UUID tree = copse.m_trees[next]; + SceneObjectGroup sog = m_scene.GetSceneObjectGroup(tree); + if (sog != null && !sog.IsDeleted) + { + if(m_allowGrow) + { + odds = sog.RootPart.Scale.Z * scale; + odds = odds * odds * odds; + odds *= (float)Util.RandomClass.NextDouble(); } else { - m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); + odds = (float)Util.RandomClass.NextDouble(); + odds = odds * odds * odds; } + + if(odds > 0.9f) + { + m_scene.DeleteSceneObject(sog, false); + if(maxbdeaths <= 0) + break; + } + } + else + { + copse.m_trees.Remove(tree); + if(copse.m_trees.Count - (int)(copse.m_tree_quantity * .98f) <= 0 ) + break; } } } } - private void SpawnChild(Copse copse, SceneObjectPart s_tree) + private void SpawnChild(Copse copse, SceneObjectPart s_tree, bool low) { Vector3 position = new Vector3(); - - double randX = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3); - double randY = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3); - + + float randX = copse.m_maximum_scale.X * 1.25f; + float randY = copse.m_maximum_scale.Y * 1.25f; + + float r = (float)Util.RandomClass.NextDouble(); + randX *= 2.0f * r - 1.0f; position.X = s_tree.AbsolutePosition.X + (float)randX; + + r = (float)Util.RandomClass.NextDouble(); + randY *= 2.0f * r - 1.0f; position.Y = s_tree.AbsolutePosition.Y + (float)randY; - if (position.X <= (m_scene.RegionInfo.RegionSizeX - 1) && position.X >= 0 && - position.Y <= (m_scene.RegionInfo.RegionSizeY - 1) && position.Y >= 0 && - Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range) - { - UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; + if (position.X > (m_scene.RegionInfo.RegionSizeX - 1) || position.X <= 0 || + position.Y > (m_scene.RegionInfo.RegionSizeY - 1) || position.Y <= 0) + return; - CreateTree(uuid, copse, position); - } + randX = position.X - copse.m_seed_point.X; + randX *= randX; + randY = position.Y - copse.m_seed_point.Y; + randY *= randY; + randX += randY; + + if(randX > copse.m_range * copse.m_range) + return; + + UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; + CreateTree(uuid, copse, position, low); } - private void CreateTree(UUID uuid, Copse copse, Vector3 position) + private void CreateTree(UUID uuid, Copse copse, Vector3 position, bool randomScale) { - position.Z = (float)m_scene.Heightmap[(int)position.X, (int)position.Y]; - if (position.Z >= copse.m_treeline_low && position.Z <= copse.m_treeline_high) - { - SceneObjectGroup tree = AddTree(uuid, UUID.Zero, copse.m_initial_scale, Quaternion.Identity, position, copse.m_tree_type, false); + if (position.Z < copse.m_treeline_low || position.Z > copse.m_treeline_high) + return; - tree.Name = copse.ToString(); - copse.m_trees.Add(tree.UUID); - tree.SendGroupFullUpdate(); + Vector3 scale = copse.m_initial_scale; + if(randomScale) + { + try + { + float t; + float r = (float)Util.RandomClass.NextDouble(); + r *= (float)Util.RandomClass.NextDouble(); + r *= (float)Util.RandomClass.NextDouble(); + + t = copse.m_maximum_scale.X / copse.m_initial_scale.X; + if(t < 1.0) + t = 1 / t; + t = t * r + 1.0f; + scale.X *= t; + + t = copse.m_maximum_scale.Y / copse.m_initial_scale.Y; + if(t < 1.0) + t = 1 / t; + t = t * r + 1.0f; + scale.Y *= t; + + t = copse.m_maximum_scale.Z / copse.m_initial_scale.Z; + if(t < 1.0) + t = 1 / t; + t = t * r + 1.0f; + scale.Z *= t; + } + catch + { + scale = copse.m_initial_scale; + } } + + SceneObjectGroup tree = AddTree(uuid, UUID.Zero, scale, Quaternion.Identity, position, copse.m_tree_type, false); + tree.Name = copse.ToString(); + copse.m_trees.Add(tree.UUID); + tree.RootPart.ScheduleFullUpdate(); } private void CalculateTrees_Elapsed(object sender, ElapsedEventArgs e) { - growTrees(); - seedTrees(); - killTrees(); + if(!m_scene.IsRunning) + return; + + if(Monitor.TryEnter(mylock)) + { + try + { + if(m_scene.LoginsEnabled ) + { + growTrees(); + seedTrees(); + killTrees(); + } + } + catch { } + if(CalculateTrees != null) + CalculateTrees.Start(); + Monitor.Exit(mylock); + } } } } -- cgit v1.1