aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/World
diff options
context:
space:
mode:
authoronefang2019-09-11 16:36:50 +1000
committeronefang2019-09-11 16:36:50 +1000
commit50cd1ffd32f69228e566f2b0b89f86ea0d9fe489 (patch)
tree52f2ab0c04f1a5d7d6ac5dc872981b4b156447e7 /OpenSim/Region/OptionalModules/World
parentRenamed branch to SledjChisl. (diff)
parentBump to release flavour, build 0. (diff)
downloadopensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.zip
opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.gz
opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.bz2
opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.xz
Merge branch 'SledjChisl'
Diffstat (limited to 'OpenSim/Region/OptionalModules/World')
-rw-r--r--OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs791
-rw-r--r--OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs70
-rw-r--r--OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs167
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs181
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs99
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs8
-rw-r--r--OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs122
-rw-r--r--OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs724
8 files changed, 1016 insertions, 1146 deletions
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
59 /// </summary> 59 /// </summary>
60 /// <remarks> 60 /// <remarks>
61 /// Config Settings Documentation. 61 /// Config Settings Documentation.
62 /// Each configuration setting can be specified in two places: OpenSim.ini or Regions.ini. 62 /// Configuration setting can be specified in two places: OpenSim.ini and/or Regions.ini.
63 /// If specified in Regions.ini, the settings should be within the region's section name. 63 ///
64 /// If specified in OpenSim.ini, the settings should be within the [AutoBackupModule] section. 64 /// OpenSim.ini only settings section [AutoBackupModule]
65 /// AutoBackupModuleEnabled: True/False. Default: False. If True, use the auto backup module.
66 /// if false module is disable and all rest is ignored
67 /// AutoBackupInterval: Double, non-negative value. Default: 720 (12 hours).
68 /// The number of minutes between each backup attempt.
69 /// AutoBackupDir: String. Default: "." (the current directory).
70 /// A directory (absolute or relative) where backups should be saved.
71 /// AutoBackupKeepFilesForDays remove files older than this number of days. 0 disables
72 ///
73 /// Next can be set on OpenSim.ini, as default, and or per region in Regions.ini
65 /// Region-specific settings take precedence. 74 /// Region-specific settings take precedence.
66 /// 75 ///
67 /// AutoBackupModuleEnabled: True/False. Default: False. If True, use the auto backup module. This setting does not support per-region basis. 76 /// AutoBackup: True/False. Default: False. If True, activate auto backup functionality.
68 /// All other settings under [AutoBackupModule] are ignored if AutoBackupModuleEnabled is false, even per-region settings! 77 /// controls backup per region, with default optionaly set on OpenSim.ini
69 /// AutoBackup: True/False. Default: False. If True, activate auto backup functionality. 78
70 /// This is the only required option for enabling auto-backup; the other options have sane defaults.
71 /// If False for a particular region, the auto-backup module becomes a no-op for the region, and all other AutoBackup* settings are ignored.
72 /// If False globally (the default), only regions that specifically override it in Regions.ini will get AutoBackup functionality.
73 /// AutoBackupInterval: Double, non-negative value. Default: 720 (12 hours).
74 /// The number of minutes between each backup attempt.
75 /// If a negative or zero value is given, it is equivalent to setting AutoBackup = False.
76 /// AutoBackupBusyCheck: True/False. Default: True.
77 /// If True, we will only take an auto-backup if a set of conditions are met.
78 /// These conditions are heuristics to try and avoid taking a backup when the sim is busy.
79 /// AutoBackupSkipAssets 79 /// AutoBackupSkipAssets
80 /// 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 80 /// 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
81 /// AutoBackupKeepFilesForDays 81 /// AutoBackupKeepFilesForDays
82 /// 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 82 /// 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
83 /// AutoBackupScript: String. Default: not specified (disabled). 83 /// AutoBackupScript: String. Default: not specified (disabled).
84 /// File path to an executable script or binary to run when an automatic backup is taken. 84 /// File path to an executable script or binary to run when an automatic backup is taken.
85 /// The file should really be (Windows) an .exe or .bat, or (Linux/Mac) a shell script or binary. 85 /// The file should really be (Windows) an .exe or .bat, or (Linux/Mac) a shell script or binary.
86 /// Trying to "run" directories, or things with weird file associations on Win32, might cause unexpected results! 86 /// Trying to "run" directories, or things with weird file associations on Win32, might cause unexpected results!
87 /// argv[1] of the executed file/script will be the file name of the generated OAR. 87 /// argv[1] of the executed file/script will be the file name of the generated OAR.
88 /// If the process can't be spawned for some reason (file not found, no execute permission, etc), write a warning to the console. 88 /// If the process can't be spawned for some reason (file not found, no execute permission, etc), write a warning to the console.
89 /// AutoBackupNaming: string. Default: Time. 89 /// AutoBackupNaming: string. Default: Time.
90 /// One of three strings (case insensitive): 90 /// One of three strings (case insensitive):
91 /// "Time": Current timestamp is appended to file name. An existing file will never be overwritten. 91 /// "Time": Current timestamp is appended to file name. An existing file will never be overwritten.
92 /// "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. 92 /// "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.
93 /// "Overwrite": Always save to file named "${AutoBackupDir}/RegionName.oar", even if we have to overwrite an existing file. 93 /// "Overwrite": Always save to file named "${AutoBackupDir}/RegionName.oar", even if we have to overwrite an existing file.
94 /// AutoBackupDir: String. Default: "." (the current directory).
95 /// A directory (absolute or relative) where backups should be saved.
96 /// AutoBackupDilationThreshold: float. Default: 0.5. Lower bound on time dilation required for BusyCheck heuristics to pass.
97 /// If the time dilation is below this value, don't take a backup right now.
98 /// AutoBackupAgentThreshold: int. Default: 10. Upper bound on # of agents in region required for BusyCheck heuristics to pass.
99 /// If the number of agents is greater than this value, don't take a backup right now
100 /// Save memory by setting low initial capacities. Minimizes impact in common cases of all regions using same interval, and instances hosting 1 ~ 4 regions.
101 /// Also helps if you don't want AutoBackup at all.
102 /// </remarks> 94 /// </remarks>
103 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AutoBackupModule")] 95 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AutoBackupModule")]
104 public class AutoBackupModule : ISharedRegionModule 96 public class AutoBackupModule : ISharedRegionModule
105 { 97 {
106 private static readonly ILog m_log = 98 private static readonly ILog m_log =
107 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 99 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
108 private readonly Dictionary<Guid, IScene> m_pendingSaves = new Dictionary<Guid, IScene>(1);
109 private readonly AutoBackupModuleState m_defaultState = new AutoBackupModuleState(); 100 private readonly AutoBackupModuleState m_defaultState = new AutoBackupModuleState();
110 private readonly Dictionary<IScene, AutoBackupModuleState> m_states = 101 private readonly Dictionary<IScene, AutoBackupModuleState> m_states =
111 new Dictionary<IScene, AutoBackupModuleState>(1); 102 new Dictionary<IScene, AutoBackupModuleState>(1);
112 private readonly Dictionary<Timer, List<IScene>> m_timerMap =
113 new Dictionary<Timer, List<IScene>>(1);
114 private readonly Dictionary<double, Timer> m_timers = new Dictionary<double, Timer>(1);
115 103
116 private delegate T DefaultGetter<T>(string settingName, T defaultValue); 104 private delegate T DefaultGetter<T>(string settingName, T defaultValue);
117 private bool m_enabled; 105 private bool m_enabled;
118 private ICommandConsole m_console; 106 private ICommandConsole m_console;
119 private List<Scene> m_Scenes = new List<Scene> (); 107 private List<Scene> m_Scenes = new List<Scene> ();
120 108 private Timer m_masterTimer;
121 109 private bool m_busy;
122 /// <summary> 110 private int m_KeepFilesForDays = -1;
123 /// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState! 111 private string m_backupDir;
124 /// </summary> 112 private bool m_doneFirst;
125 private bool m_closed; 113 private double m_baseInterval;
126 114
127 private IConfigSource m_configSource; 115 private IConfigSource m_configSource;
128 116
@@ -159,36 +147,38 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
159 void IRegionModuleBase.Initialise(IConfigSource source) 147 void IRegionModuleBase.Initialise(IConfigSource source)
160 { 148 {
161 // Determine if we have been enabled at all in OpenSim.ini -- this is part and parcel of being an optional module 149 // Determine if we have been enabled at all in OpenSim.ini -- this is part and parcel of being an optional module
162 this.m_configSource = source; 150 m_configSource = source;
163 IConfig moduleConfig = source.Configs["AutoBackupModule"]; 151 IConfig moduleConfig = source.Configs["AutoBackupModule"];
164 if (moduleConfig == null) 152 if (moduleConfig == null)
165 { 153 {
166 this.m_enabled = false; 154 m_enabled = false;
167 return; 155 return;
168 } 156 }
169 else
170 {
171 this.m_enabled = moduleConfig.GetBoolean("AutoBackupModuleEnabled", false);
172 if (this.m_enabled)
173 {
174 m_log.Info("[AUTO BACKUP]: AutoBackupModule enabled");
175 }
176 else
177 {
178 return;
179 }
180 }
181 157
182 Timer defTimer = new Timer(43200000); 158 m_enabled = moduleConfig.GetBoolean("AutoBackupModuleEnabled", false);
183 this.m_defaultState.Timer = defTimer; 159 if(!m_enabled)
184 this.m_timers.Add(43200000, defTimer); 160 return;
185 defTimer.Elapsed += this.HandleElapsed; 161
186 defTimer.AutoReset = true; 162 ParseDefaultConfig(moduleConfig);
187 defTimer.Start(); 163 if(!m_enabled)
164 return;
165
166 m_log.Debug("[AUTO BACKUP]: Default config:");
167 m_log.Debug(m_defaultState.ToString());
168
169 m_log.Info("[AUTO BACKUP]: AutoBackupModule enabled");
170 m_masterTimer = new Timer();
171 m_masterTimer.Interval = m_baseInterval;
172 m_masterTimer.Elapsed += HandleElapsed;
173 m_masterTimer.AutoReset = false;
174
175 m_console = MainConsole.Instance;
188 176
189 AutoBackupModuleState abms = this.ParseConfig(null, true); 177 m_console.Commands.AddCommand (
190 m_log.Debug("[AUTO BACKUP]: Here is the default config:"); 178 "AutoBackup", true, "dooarbackup",
191 m_log.Debug(abms.ToString()); 179 "dooarbackup <regionName> | ALL",
180 "saves the single region <regionName> to a oar or ALL regions in instance to oars, using same settings as AutoBackup. Note it restarts time interval", DoBackup);
181 m_busy = true;
192 } 182 }
193 183
194 /// <summary> 184 /// <summary>
@@ -196,13 +186,11 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
196 /// </summary> 186 /// </summary>
197 void IRegionModuleBase.Close() 187 void IRegionModuleBase.Close()
198 { 188 {
199 if (!this.m_enabled) 189 if (!m_enabled)
200 {
201 return; 190 return;
202 }
203 191
204 // We don't want any timers firing while the sim's coming down; strange things may happen. 192 // We don't want any timers firing while the sim's coming down; strange things may happen.
205 this.StopAllTimers(); 193 m_masterTimer.Dispose();
206 } 194 }
207 195
208 /// <summary> 196 /// <summary>
@@ -211,18 +199,11 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
211 /// <param name="scene"></param> 199 /// <param name="scene"></param>
212 void IRegionModuleBase.AddRegion (Scene scene) 200 void IRegionModuleBase.AddRegion (Scene scene)
213 { 201 {
214 if (!this.m_enabled) { 202 if (!m_enabled)
215 return; 203 return;
216 }
217 lock (m_Scenes) {
218 m_Scenes.Add (scene);
219 }
220 m_console = MainConsole.Instance;
221 204
222 m_console.Commands.AddCommand ( 205 lock (m_Scenes)
223 "AutoBackup", false, "dobackup", 206 m_Scenes.Add (scene);
224 "dobackup",
225 "do backup.", DoBackup);
226 } 207 }
227 208
228 /// <summary> 209 /// <summary>
@@ -231,28 +212,14 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
231 /// <param name="scene">The scene (region) to stop performing AutoBackup on.</param> 212 /// <param name="scene">The scene (region) to stop performing AutoBackup on.</param>
232 void IRegionModuleBase.RemoveRegion(Scene scene) 213 void IRegionModuleBase.RemoveRegion(Scene scene)
233 { 214 {
234 if (!this.m_enabled) 215 if (m_enabled)
235 {
236 return; 216 return;
237 }
238 m_Scenes.Remove (scene);
239 if (this.m_states.ContainsKey(scene))
240 {
241 AutoBackupModuleState abms = this.m_states[scene];
242 217
243 // Remove this scene out of the timer map list 218 lock(m_Scenes)
244 Timer timer = abms.Timer; 219 {
245 List<IScene> list = this.m_timerMap[timer]; 220 if (m_states.ContainsKey(scene))
246 list.Remove(scene); 221 m_states.Remove(scene);
247 222 m_Scenes.Remove(scene);
248 // Shut down the timer if this was the last scene for the timer
249 if (list.Count == 0)
250 {
251 this.m_timerMap.Remove(timer);
252 this.m_timers.Remove(timer.Interval);
253 timer.Close();
254 }
255 this.m_states.Remove(scene);
256 } 223 }
257 } 224 }
258 225
@@ -263,22 +230,29 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
263 /// <param name="scene">The scene to (possibly) perform AutoBackup on.</param> 230 /// <param name="scene">The scene to (possibly) perform AutoBackup on.</param>
264 void IRegionModuleBase.RegionLoaded(Scene scene) 231 void IRegionModuleBase.RegionLoaded(Scene scene)
265 { 232 {
266 if (!this.m_enabled) 233 if (!m_enabled)
267 {
268 return; 234 return;
269 }
270 235
271 // This really ought not to happen, but just in case, let's pretend it didn't... 236 // This really ought not to happen, but just in case, let's pretend it didn't...
272 if (scene == null) 237 if (scene == null)
273 {
274 return; 238 return;
275 }
276 239
277 AutoBackupModuleState abms = this.ParseConfig(scene, false); 240 AutoBackupModuleState abms = ParseConfig(scene);
278 m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName); 241 if(abms == null)
279 m_log.Debug((abms == null ? "DEFAULT" : abms.ToString())); 242 {
243 m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName);
244 m_log.Debug("DEFAULT");
245 abms = new AutoBackupModuleState(m_defaultState);
246 }
247 else
248 {
249 m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName);
250 m_log.Debug(abms.ToString());
251 }
280 252
281 m_states.Add(scene, abms); 253 m_states.Add(scene, abms);
254 m_busy = false;
255 m_masterTimer.Start();
282 } 256 }
283 257
284 /// <summary> 258 /// <summary>
@@ -292,356 +266,174 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
292 266
293 private void DoBackup (string module, string[] args) 267 private void DoBackup (string module, string[] args)
294 { 268 {
295 if (args.Length != 2) { 269 if (!m_enabled)
296 MainConsole.Instance.OutputFormat ("Usage: dobackup <regionname>");
297 return; 270 return;
298 }
299 bool found = false;
300 string name = args [1];
301 lock (m_Scenes) {
302 foreach (Scene s in m_Scenes) {
303 string test = s.Name.ToString ();
304 if (test == name) {
305 found = true;
306 DoRegionBackup (s);
307 }
308 }
309 if (!found) {
310 MainConsole.Instance.OutputFormat ("No such region {0}. Nothing to backup", name);
311 }
312 }
313 }
314 271
315 /// <summary> 272 if (args.Length != 2)
316 /// Set up internal state for a given scene. Fairly complex code.
317 /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene.
318 /// </summary>
319 /// <param name="scene">The scene to look at.</param>
320 /// <param name="parseDefault">Whether this call is intended to figure out what we consider the "default" config (applied to all regions unless overridden by per-region settings).</param>
321 /// <returns>An AutoBackupModuleState contains most information you should need to know relevant to auto-backup, as applicable to a single region.</returns>
322 private AutoBackupModuleState ParseConfig(IScene scene, bool parseDefault)
323 {
324 string sRegionName;
325 string sRegionLabel;
326// string prepend;
327 AutoBackupModuleState state;
328
329 if (parseDefault)
330 {
331 sRegionName = null;
332 sRegionLabel = "DEFAULT";
333// prepend = "";
334 state = this.m_defaultState;
335 }
336 else
337 {
338 sRegionName = scene.RegionInfo.RegionName;
339 sRegionLabel = sRegionName;
340// prepend = sRegionName + ".";
341 state = null;
342 }
343
344 // Read the config settings and set variables.
345 IConfig regionConfig = (scene != null ? scene.Config.Configs[sRegionName] : null);
346 IConfig config = this.m_configSource.Configs["AutoBackupModule"];
347 if (config == null)
348 { 273 {
349 // defaultState would be disabled too if the section doesn't exist. 274 MainConsole.Instance.OutputFormat ("Usage: dooarbackup <regionname>");
350 state = this.m_defaultState; 275 return;
351 return state;
352 }
353
354 bool tmpEnabled = ResolveBoolean("AutoBackup", this.m_defaultState.Enabled, config, regionConfig);
355 if (state == null && tmpEnabled != this.m_defaultState.Enabled)
356 //Varies from default state
357 {
358 state = new AutoBackupModuleState();
359 } 276 }
360 277
361 if (state != null) 278 if(m_busy)
362 { 279 {
363 state.Enabled = tmpEnabled; 280 MainConsole.Instance.OutputFormat ("Already doing a backup, please try later");
281 return;
364 } 282 }
365 283
366 // If you don't want AutoBackup, we stop. 284 m_masterTimer.Stop();
367 if ((state == null && !this.m_defaultState.Enabled) || (state != null && !state.Enabled)) 285 m_busy = true;
368 {
369 return state;
370 }
371 else
372 {
373 m_log.Info("[AUTO BACKUP]: Region " + sRegionLabel + " is AutoBackup ENABLED.");
374 }
375 286
376 // Borrow an existing timer if one exists for the same interval; otherwise, make a new one. 287 bool found = false;
377 double interval = 288 string name = args [1];
378 this.ResolveDouble("AutoBackupInterval", this.m_defaultState.IntervalMinutes, 289 Scene[] scenes;
379 config, regionConfig) * 60000.0; 290 lock (m_Scenes)
380 if (state == null && interval != this.m_defaultState.IntervalMinutes * 60000.0) 291 scenes = m_Scenes.ToArray();
381 {
382 state = new AutoBackupModuleState();
383 }
384 292
385 if (this.m_timers.ContainsKey(interval)) 293 if(scenes == null)
386 { 294 return;
387 if (state != null)
388 {
389 state.Timer = this.m_timers[interval];
390 }
391 m_log.Debug("[AUTO BACKUP]: Reusing timer for " + interval + " msec for region " +
392 sRegionLabel);
393 }
394 else
395 {
396 // 0 or negative interval == do nothing.
397 if (interval <= 0.0 && state != null)
398 {
399 state.Enabled = false;
400 return state;
401 }
402 if (state == null)
403 {
404 state = new AutoBackupModuleState();
405 }
406 Timer tim = new Timer(interval);
407 state.Timer = tim;
408 //Milliseconds -> minutes
409 this.m_timers.Add(interval, tim);
410 tim.Elapsed += this.HandleElapsed;
411 tim.AutoReset = true;
412 tim.Start();
413 }
414 295
415 // Add the current region to the list of regions tied to this timer. 296 Scene s;
416 if (scene != null) 297 try
417 { 298 {
418 if (state != null) 299 if(name == "ALL")
419 { 300 {
420 if (this.m_timerMap.ContainsKey(state.Timer)) 301 for(int i = 0; i < scenes.Length; i++)
421 { 302 {
422 this.m_timerMap[state.Timer].Add(scene); 303 s = scenes[i];
423 } 304 DoRegionBackup(s);
424 else 305 if (!m_enabled)
425 { 306 return;
426 List<IScene> scns = new List<IScene>(1);
427 scns.Add(scene);
428 this.m_timerMap.Add(state.Timer, scns);
429 } 307 }
308 return;
430 } 309 }
431 else 310
311 for(int i = 0; i < scenes.Length; i++)
432 { 312 {
433 if (this.m_timerMap.ContainsKey(this.m_defaultState.Timer)) 313 s = scenes[i];
314 if (s.Name == name)
434 { 315 {
435 this.m_timerMap[this.m_defaultState.Timer].Add(scene); 316 found = true;
436 } 317 DoRegionBackup(s);
437 else 318 break;
438 {
439 List<IScene> scns = new List<IScene>(1);
440 scns.Add(scene);
441 this.m_timerMap.Add(this.m_defaultState.Timer, scns);
442 } 319 }
443 } 320 }
444 } 321 }
445 322 catch { }
446 bool tmpBusyCheck = ResolveBoolean("AutoBackupBusyCheck", 323 finally
447 this.m_defaultState.BusyCheck, config, regionConfig);
448 if (state == null && tmpBusyCheck != this.m_defaultState.BusyCheck)
449 { 324 {
450 state = new AutoBackupModuleState(); 325 if (m_enabled)
451 } 326 m_masterTimer.Start();
327 m_busy = false;
328 }
329 if (!found)
330 MainConsole.Instance.OutputFormat ("No such region {0}. Nothing to backup", name);
331 }
452 332
453 if (state != null) 333 private void ParseDefaultConfig(IConfig config)
454 { 334 {
455 state.BusyCheck = tmpBusyCheck;
456 }
457 335
458 // Included Option To Skip Assets 336 m_backupDir = ".";
459 bool tmpSkipAssets = ResolveBoolean("AutoBackupSkipAssets", 337 string backupDir = config.GetString("AutoBackupDir", ".");
460 this.m_defaultState.SkipAssets, config, regionConfig); 338 if (backupDir != ".")
461 if (state == null && tmpSkipAssets != this.m_defaultState.SkipAssets)
462 { 339 {
463 state = new AutoBackupModuleState(); 340 try
341 {
342 DirectoryInfo dirinfo = new DirectoryInfo(backupDir);
343 if (!dirinfo.Exists)
344 dirinfo.Create();
345 }
346 catch (Exception e)
347 {
348 m_enabled = false;
349 m_log.WarnFormat("[AUTO BACKUP]: Error accessing backup folder {0}. Module disabled. {1}",
350 backupDir, e);
351 return;
352 }
464 } 353 }
354 m_backupDir = backupDir;
465 355
466 if (state != null) 356 double interval = config.GetDouble("AutoBackupInterval", 720);
467 { 357 interval *= 60000.0;
468 state.SkipAssets = tmpSkipAssets; 358 m_baseInterval = interval;
469 }
470 359
471 // How long to keep backup files in days, 0 Disables this feature 360 // How long to keep backup files in days, 0 Disables this feature
472 int tmpKeepFilesForDays = ResolveInt("AutoBackupKeepFilesForDays", 361 m_KeepFilesForDays = config.GetInt("AutoBackupKeepFilesForDays",m_KeepFilesForDays);
473 this.m_defaultState.KeepFilesForDays, config, regionConfig);
474 if (state == null && tmpKeepFilesForDays != this.m_defaultState.KeepFilesForDays)
475 {
476 state = new AutoBackupModuleState();
477 }
478 362
479 if (state != null) 363 m_defaultState.Enabled = config.GetBoolean("AutoBackup", m_defaultState.Enabled);
480 { 364
481 state.KeepFilesForDays = tmpKeepFilesForDays; 365 m_defaultState.SkipAssets = config.GetBoolean("AutoBackupSkipAssets",m_defaultState.SkipAssets);
482 }
483 366
484 // Set file naming algorithm 367 // Set file naming algorithm
485 string stmpNamingType = ResolveString("AutoBackupNaming", 368 string stmpNamingType = config.GetString("AutoBackupNaming", m_defaultState.NamingType.ToString());
486 this.m_defaultState.NamingType.ToString(), config, regionConfig);
487 NamingType tmpNamingType; 369 NamingType tmpNamingType;
488 if (stmpNamingType.Equals("Time", StringComparison.CurrentCultureIgnoreCase)) 370 if (stmpNamingType.Equals("Time", StringComparison.CurrentCultureIgnoreCase))
489 {
490 tmpNamingType = NamingType.Time; 371 tmpNamingType = NamingType.Time;
491 }
492 else if (stmpNamingType.Equals("Sequential", StringComparison.CurrentCultureIgnoreCase)) 372 else if (stmpNamingType.Equals("Sequential", StringComparison.CurrentCultureIgnoreCase))
493 {
494 tmpNamingType = NamingType.Sequential; 373 tmpNamingType = NamingType.Sequential;
495 }
496 else if (stmpNamingType.Equals("Overwrite", StringComparison.CurrentCultureIgnoreCase)) 374 else if (stmpNamingType.Equals("Overwrite", StringComparison.CurrentCultureIgnoreCase))
497 {
498 tmpNamingType = NamingType.Overwrite; 375 tmpNamingType = NamingType.Overwrite;
499 }
500 else 376 else
501 { 377 {
502 m_log.Warn("Unknown naming type specified for region " + sRegionLabel + ": " + 378 m_log.Warn("Unknown naming type specified for Default");
503 stmpNamingType);
504 tmpNamingType = NamingType.Time; 379 tmpNamingType = NamingType.Time;
505 } 380 }
381 m_defaultState.NamingType = tmpNamingType;
506 382
507 if (state == null && tmpNamingType != this.m_defaultState.NamingType) 383 m_defaultState.Script = config.GetString("AutoBackupScript", m_defaultState.Script);
508 {
509 state = new AutoBackupModuleState();
510 }
511 384
512 if (state != null) 385 }
513 {
514 state.NamingType = tmpNamingType;
515 }
516 386
517 string tmpScript = ResolveString("AutoBackupScript", 387 /// <summary>
518 this.m_defaultState.Script, config, regionConfig); 388 /// Set up internal state for a given scene. Fairly complex code.
519 if (state == null && tmpScript != this.m_defaultState.Script) 389 /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene.
520 { 390 /// </summary>
521 state = new AutoBackupModuleState(); 391 /// <param name="scene">The scene to look at.</param>
522 } 392 /// <param name="parseDefault">Whether this call is intended to figure out what we consider the "default" config (applied to all regions unless overridden by per-region settings).</param>
393 /// <returns>An AutoBackupModuleState contains most information you should need to know relevant to auto-backup, as applicable to a single region.</returns>
394 private AutoBackupModuleState ParseConfig(IScene scene)
395 {
396 if(scene == null)
397 return null;
523 398
524 if (state != null) 399 string sRegionName;
525 { 400 AutoBackupModuleState state = null;
526 state.Script = tmpScript;
527 }
528 401
529 string tmpBackupDir = ResolveString("AutoBackupDir", ".", config, regionConfig); 402 sRegionName = scene.RegionInfo.RegionName;
530 if (state == null && tmpBackupDir != this.m_defaultState.BackupDir)
531 {
532 state = new AutoBackupModuleState();
533 }
534 403
535 if (state != null) 404 // Read the config settings and set variables.
536 { 405 IConfig regionConfig = scene.Config.Configs[sRegionName];
537 state.BackupDir = tmpBackupDir; 406 if (regionConfig == null)
538 // Let's give the user some convenience and auto-mkdir 407 return null;
539 if (state.BackupDir != ".")
540 {
541 try
542 {
543 DirectoryInfo dirinfo = new DirectoryInfo(state.BackupDir);
544 if (!dirinfo.Exists)
545 {
546 dirinfo.Create();
547 }
548 }
549 catch (Exception e)
550 {
551 m_log.Warn(
552 "[AUTO BACKUP]: BAD NEWS. You won't be able to save backups to directory " +
553 state.BackupDir +
554 " because it doesn't exist or there's a permissions issue with it. Here's the exception.",
555 e);
556 }
557 }
558 }
559 408
560 if(state == null) 409 state = new AutoBackupModuleState();
561 return m_defaultState;
562 410
563 return state; 411 state.Enabled = regionConfig.GetBoolean("AutoBackup", m_defaultState.Enabled);
564 }
565 412
566 /// <summary> 413 // Included Option To Skip Assets
567 /// Helper function for ParseConfig. 414 state.SkipAssets = regionConfig.GetBoolean("AutoBackupSkipAssets", m_defaultState.SkipAssets);
568 /// </summary>
569 /// <param name="settingName"></param>
570 /// <param name="defaultValue"></param>
571 /// <param name="global"></param>
572 /// <param name="local"></param>
573 /// <returns></returns>
574 private bool ResolveBoolean(string settingName, bool defaultValue, IConfig global, IConfig local)
575 {
576 if(local != null)
577 {
578 return local.GetBoolean(settingName, global.GetBoolean(settingName, defaultValue));
579 }
580 else
581 {
582 return global.GetBoolean(settingName, defaultValue);
583 }
584 }
585 415
586 /// <summary> 416 // Set file naming algorithm
587 /// Helper function for ParseConfig. 417 string stmpNamingType = regionConfig.GetString("AutoBackupNaming", m_defaultState.NamingType.ToString());
588 /// </summary> 418 NamingType tmpNamingType;
589 /// <param name="settingName"></param> 419 if (stmpNamingType.Equals("Time", StringComparison.CurrentCultureIgnoreCase))
590 /// <param name="defaultValue"></param> 420 tmpNamingType = NamingType.Time;
591 /// <param name="global"></param> 421 else if (stmpNamingType.Equals("Sequential", StringComparison.CurrentCultureIgnoreCase))
592 /// <param name="local"></param> 422 tmpNamingType = NamingType.Sequential;
593 /// <returns></returns> 423 else if (stmpNamingType.Equals("Overwrite", StringComparison.CurrentCultureIgnoreCase))
594 private double ResolveDouble(string settingName, double defaultValue, IConfig global, IConfig local) 424 tmpNamingType = NamingType.Overwrite;
595 {
596 if (local != null)
597 {
598 return local.GetDouble(settingName, global.GetDouble(settingName, defaultValue));
599 }
600 else 425 else
601 { 426 {
602 return global.GetDouble(settingName, defaultValue); 427 m_log.Warn("Unknown naming type specified for region " + sRegionName + ": " +
428 stmpNamingType);
429 tmpNamingType = NamingType.Time;
603 } 430 }
604 } 431 m_defaultState.NamingType = tmpNamingType;
605 432
606 /// <summary> 433 state.Script = regionConfig.GetString("AutoBackupScript", m_defaultState.Script);
607 /// Helper function for ParseConfig. 434 return state;
608 /// </summary>
609 /// <param name="settingName"></param>
610 /// <param name="defaultValue"></param>
611 /// <param name="global"></param>
612 /// <param name="local"></param>
613 /// <returns></returns>
614 private int ResolveInt(string settingName, int defaultValue, IConfig global, IConfig local)
615 {
616 if (local != null)
617 {
618 return local.GetInt(settingName, global.GetInt(settingName, defaultValue));
619 }
620 else
621 {
622 return global.GetInt(settingName, defaultValue);
623 }
624 } 435 }
625 436
626 /// <summary>
627 /// Helper function for ParseConfig.
628 /// </summary>
629 /// <param name="settingName"></param>
630 /// <param name="defaultValue"></param>
631 /// <param name="global"></param>
632 /// <param name="local"></param>
633 /// <returns></returns>
634 private string ResolveString(string settingName, string defaultValue, IConfig global, IConfig local)
635 {
636 if (local != null)
637 {
638 return local.GetString(settingName, global.GetString(settingName, defaultValue));
639 }
640 else
641 {
642 return global.GetString(settingName, defaultValue);
643 }
644 }
645 437
646 /// <summary> 438 /// <summary>
647 /// Called when any auto-backup timer expires. This starts the code path for actually performing a backup. 439 /// 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
650 /// <param name="e"></param> 442 /// <param name="e"></param>
651 private void HandleElapsed(object sender, ElapsedEventArgs e) 443 private void HandleElapsed(object sender, ElapsedEventArgs e)
652 { 444 {
653 // TODO: heuristic thresholds are per-region, so we should probably run heuristics once per region 445 if (!m_enabled || m_busy)
654 // XXX: Running heuristics once per region could add undue performance penalty for something that's supposed to
655 // check whether the region is too busy! Especially on sims with LOTS of regions.
656 // Alternative: make heuristics thresholds global to the module rather than per-region. Less flexible,
657 // but would allow us to be semantically correct while being easier on perf.
658 // Alternative 2: Run heuristics once per unique set of heuristics threshold parameters! Ay yi yi...
659 // Alternative 3: Don't support per-region heuristics at all; just accept them as a global only parameter.
660 // Since this is pretty experimental, I haven't decided which alternative makes the most sense.
661 if (this.m_closed)
662 {
663 return; 446 return;
664 } 447
665 bool heuristicsRun = false; 448 m_busy = true;
666 bool heuristicsPassed = false; 449 if(m_doneFirst && m_KeepFilesForDays > 0)
667 if (!this.m_timerMap.ContainsKey((Timer) sender)) 450 RemoveOldFiles();
451
452 foreach (IScene scene in m_Scenes)
668 { 453 {
669 m_log.Debug("[AUTO BACKUP]: Code-up error: timerMap doesn't contain timer " + sender); 454 if (!m_enabled)
455 return;
456 DoRegionBackup(scene);
670 } 457 }
671 458
672 List<IScene> tmap = this.m_timerMap[(Timer) sender]; 459 if (m_enabled)
673 if (tmap != null && tmap.Count > 0)
674 { 460 {
675 foreach (IScene scene in tmap) 461 m_masterTimer.Start();
676 { 462 m_busy = false;
677 AutoBackupModuleState state = this.m_states[scene];
678 bool heuristics = state.BusyCheck;
679
680 // Fast path: heuristics are on; already ran em; and sim is fine; OR, no heuristics for the region.
681 if ((heuristics && heuristicsRun && heuristicsPassed) || !heuristics)
682 {
683 this.DoRegionBackup(scene);
684 // Heuristics are on; ran but we're too busy -- keep going. Maybe another region will have heuristics off!
685 }
686 else if (heuristicsRun)
687 {
688 m_log.Info("[AUTO BACKUP]: Heuristics: too busy to backup " +
689 scene.RegionInfo.RegionName + " right now.");
690 continue;
691 // Logical Deduction: heuristics are on but haven't been run
692 }
693 else
694 {
695 heuristicsPassed = this.RunHeuristics(scene);
696 heuristicsRun = true;
697 if (!heuristicsPassed)
698 {
699 m_log.Info("[AUTO BACKUP]: Heuristics: too busy to backup " +
700 scene.RegionInfo.RegionName + " right now.");
701 continue;
702 }
703 this.DoRegionBackup(scene);
704 }
705
706 // Remove Old Backups
707 this.RemoveOldFiles(state);
708 }
709 } 463 }
464
465 m_doneFirst = true;
710 } 466 }
711 467
712 /// <summary> 468 /// <summary>
@@ -723,21 +479,29 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
723 return; 479 return;
724 } 480 }
725 481
726 AutoBackupModuleState state = this.m_states[scene]; 482 m_busy = true;
483
484 AutoBackupModuleState state;
485 if(!m_states.TryGetValue(scene, out state))
486 return;
487
488 if(state == null || !state.Enabled)
489 return;
490
727 IRegionArchiverModule iram = scene.RequestModuleInterface<IRegionArchiverModule>(); 491 IRegionArchiverModule iram = scene.RequestModuleInterface<IRegionArchiverModule>();
492 if(iram == null)
493 return;
494
728 string savePath = BuildOarPath(scene.RegionInfo.RegionName, 495 string savePath = BuildOarPath(scene.RegionInfo.RegionName,
729 state.BackupDir, 496 m_backupDir,
730 state.NamingType); 497 state.NamingType);
731 if (savePath == null) 498 if (savePath == null)
732 { 499 {
733 m_log.Warn("[AUTO BACKUP]: savePath is null in HandleElapsed"); 500 m_log.Warn("[AUTO BACKUP]: savePath is null in HandleElapsed");
734 return; 501 return;
735 } 502 }
736 Guid guid = Guid.NewGuid();
737 m_pendingSaves.Add(guid, scene);
738 state.LiveRequests.Add(guid, savePath);
739 ((Scene) scene).EventManager.OnOarFileSaved += new EventManager.OarFileSaved(EventManager_OnOarFileSaved);
740 503
504 Guid guid = Guid.NewGuid();
741 m_log.Info("[AUTO BACKUP]: Backing up region " + scene.RegionInfo.RegionName); 505 m_log.Info("[AUTO BACKUP]: Backing up region " + scene.RegionInfo.RegionName);
742 506
743 // Must pass options, even if dictionary is empty! 507 // Must pass options, even if dictionary is empty!
@@ -747,47 +511,37 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
747 options["noassets"] = true; 511 options["noassets"] = true;
748 512
749 iram.ArchiveRegion(savePath, guid, options); 513 iram.ArchiveRegion(savePath, guid, options);
514 ExecuteScript(state.Script, savePath);
750 } 515 }
751 516
752 // For the given state, remove backup files older than the states KeepFilesForDays property 517 // For the given state, remove backup files older than the states KeepFilesForDays property
753 private void RemoveOldFiles(AutoBackupModuleState state) 518 private void RemoveOldFiles()
754 { 519 {
755 // 0 Means Disabled, Keep Files Indefinitely 520 string[] files;
756 if (state.KeepFilesForDays > 0) 521 try
757 { 522 {
758 string[] files = Directory.GetFiles(state.BackupDir, "*.oar"); 523 files = Directory.GetFiles(m_backupDir, "*.oar");
759 DateTime CuttOffDate = DateTime.Now.AddDays(0 - state.KeepFilesForDays); 524 }
760 525 catch (Exception Ex)
761 foreach (string file in files) 526 {
762 { 527 m_log.Error("[AUTO BACKUP]: Error reading backup folder " + m_backupDir + ": " + Ex.Message);
763 try 528 return;
764 {
765 FileInfo fi = new FileInfo(file);
766 if (fi.CreationTime < CuttOffDate)
767 fi.Delete();
768 }
769 catch (Exception Ex)
770 {
771 m_log.Error("[AUTO BACKUP]: Error deleting old backup file '" + file + "': " + Ex.Message);
772 }
773 }
774 } 529 }
775 }
776 530
777 /// <summary> 531 DateTime CuttOffDate = DateTime.Now.AddDays(-m_KeepFilesForDays);
778 /// Called by the Event Manager when the OnOarFileSaved event is fired. 532
779 /// </summary> 533 foreach (string file in files)
780 /// <param name="guid"></param>
781 /// <param name="message"></param>
782 void EventManager_OnOarFileSaved(Guid guid, string message)
783 {
784 // Ignore if the OAR save is being done by some other part of the system
785 if (m_pendingSaves.ContainsKey(guid))
786 { 534 {
787 AutoBackupModuleState abms = m_states[(m_pendingSaves[guid])]; 535 try
788 ExecuteScript(abms.Script, abms.LiveRequests[guid]); 536 {
789 m_pendingSaves.Remove(guid); 537 FileInfo fi = new FileInfo(file);
790 abms.LiveRequests.Remove(guid); 538 if (fi.CreationTime < CuttOffDate)
539 fi.Delete();
540 }
541 catch (Exception Ex)
542 {
543 m_log.Error("[AUTO BACKUP]: Error deleting old backup file '" + file + "': " + Ex.Message);
544 }
791 } 545 }
792 } 546 }
793 547
@@ -817,63 +571,6 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
817 return output; 571 return output;
818 } 572 }
819 573
820 /// <summary>Return value of true ==> not too busy; false ==> too busy to backup an OAR right now, or error.</summary>
821 private bool RunHeuristics(IScene region)
822 {
823 try
824 {
825 return this.RunTimeDilationHeuristic(region) && this.RunAgentLimitHeuristic(region);
826 }
827 catch (Exception e)
828 {
829 m_log.Warn("[AUTO BACKUP]: Exception in RunHeuristics", e);
830 return false;
831 }
832 }
833
834 /// <summary>
835 /// If the time dilation right at this instant is less than the threshold specified in AutoBackupDilationThreshold (default 0.5),
836 /// then we return false and trip the busy heuristic's "too busy" path (i.e. don't save an OAR).
837 /// AutoBackupDilationThreshold is a _LOWER BOUND_. Lower Time Dilation is bad, so if you go lower than our threshold, it's "too busy".
838 /// </summary>
839 /// <param name="region"></param>
840 /// <returns>Returns true if we're not too busy; false means we've got worse time dilation than the threshold.</returns>
841 private bool RunTimeDilationHeuristic(IScene region)
842 {
843 string regionName = region.RegionInfo.RegionName;
844 return region.TimeDilation >=
845 this.m_configSource.Configs["AutoBackupModule"].GetFloat(
846 regionName + ".AutoBackupDilationThreshold", 0.5f);
847 }
848
849 /// <summary>
850 /// If the root agent count right at this instant is less than the threshold specified in AutoBackupAgentThreshold (default 10),
851 /// then we return false and trip the busy heuristic's "too busy" path (i.e., don't save an OAR).
852 /// AutoBackupAgentThreshold is an _UPPER BOUND_. Higher Agent Count is bad, so if you go higher than our threshold, it's "too busy".
853 /// </summary>
854 /// <param name="region"></param>
855 /// <returns>Returns true if we're not too busy; false means we've got more agents on the sim than the threshold.</returns>
856 private bool RunAgentLimitHeuristic(IScene region)
857 {
858 string regionName = region.RegionInfo.RegionName;
859 try
860 {
861 Scene scene = (Scene) region;
862 // TODO: Why isn't GetRootAgentCount() a method in the IScene interface? Seems generally useful...
863 return scene.GetRootAgentCount() <=
864 this.m_configSource.Configs["AutoBackupModule"].GetInt(
865 regionName + ".AutoBackupAgentThreshold", 10);
866 }
867 catch (InvalidCastException ice)
868 {
869 m_log.Debug(
870 "[AUTO BACKUP]: I NEED MAINTENANCE: IScene is not a Scene; can't get root agent count!",
871 ice);
872 return true;
873 // Non-obstructionist safest answer...
874 }
875 }
876
877 /// <summary> 574 /// <summary>
878 /// Run the script or executable specified by the "AutoBackupScript" config setting. 575 /// Run the script or executable specified by the "AutoBackupScript" config setting.
879 /// Of course this is a security risk if you let anyone modify OpenSim.ini and they want to run some nasty bash script. 576 /// 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
920 } 617 }
921 618
922 /// <summary> 619 /// <summary>
923 /// Quickly stop all timers from firing.
924 /// </summary>
925 private void StopAllTimers()
926 {
927 foreach (Timer t in this.m_timerMap.Keys)
928 {
929 t.Close();
930 }
931 this.m_closed = true;
932 }
933
934 /// <summary>
935 /// Determine the next unique filename by number, for "Sequential" AutoBackupNamingType. 620 /// Determine the next unique filename by number, for "Sequential" AutoBackupNamingType.
936 /// </summary> 621 /// </summary>
937 /// <param name="dirName"></param> 622 /// <param name="dirName"></param>
@@ -1033,5 +718,3 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
1033 } 718 }
1034 } 719 }
1035} 720}
1036
1037
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
35 /// If you use this class in any way outside of AutoBackupModule, you should treat the class as opaque. 35 /// If you use this class in any way outside of AutoBackupModule, you should treat the class as opaque.
36 /// Since it is not part of the framework, you really should not rely upon it outside of the AutoBackupModule implementation. 36 /// Since it is not part of the framework, you really should not rely upon it outside of the AutoBackupModule implementation.
37 /// </summary> 37 /// </summary>
38 /// 38 ///
39 public class AutoBackupModuleState 39 public class AutoBackupModuleState
40 { 40 {
41 private Dictionary<Guid, string> m_liveRequests = null;
42
43 public AutoBackupModuleState() 41 public AutoBackupModuleState()
44 { 42 {
45 this.Enabled = false; 43 Enabled = false;
46 this.BackupDir = "."; 44 SkipAssets = false;
47 this.BusyCheck = true; 45 NamingType = NamingType.Time;
48 this.SkipAssets = false; 46 Script = null;
49 this.Timer = null;
50 this.NamingType = NamingType.Time;
51 this.Script = null;
52 this.KeepFilesForDays = 0;
53 } 47 }
54 48
55 public Dictionary<Guid, string> LiveRequests 49 public AutoBackupModuleState(AutoBackupModuleState copyFrom)
56 { 50 {
57 get { 51 Enabled = copyFrom.Enabled;
58 return this.m_liveRequests ?? 52 SkipAssets = copyFrom.SkipAssets;
59 (this.m_liveRequests = new Dictionary<Guid, string>(1)); 53 NamingType = copyFrom.NamingType;
60 } 54 Script = copyFrom.Script;
61 } 55 }
62 56
63 public bool Enabled 57 public bool Enabled
@@ -66,33 +60,6 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
66 set; 60 set;
67 } 61 }
68 62
69 public System.Timers.Timer Timer
70 {
71 get;
72 set;
73 }
74
75 public double IntervalMinutes
76 {
77 get
78 {
79 if (this.Timer == null)
80 {
81 return -1.0;
82 }
83 else
84 {
85 return this.Timer.Interval / 60000.0;
86 }
87 }
88 }
89
90 public bool BusyCheck
91 {
92 get;
93 set;
94 }
95
96 public bool SkipAssets 63 public bool SkipAssets
97 { 64 {
98 get; 65 get;
@@ -105,36 +72,19 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
105 set; 72 set;
106 } 73 }
107 74
108 public string BackupDir
109 {
110 get;
111 set;
112 }
113
114 public NamingType NamingType 75 public NamingType NamingType
115 { 76 {
116 get; 77 get;
117 set; 78 set;
118 } 79 }
119 80
120 public int KeepFilesForDays
121 {
122 get;
123 set;
124 }
125
126 public new string ToString() 81 public new string ToString()
127 { 82 {
128 string retval = ""; 83 string retval = "";
129
130 retval += "[AUTO BACKUP]: AutoBackup: " + (Enabled ? "ENABLED" : "DISABLED") + "\n"; 84 retval += "[AUTO BACKUP]: AutoBackup: " + (Enabled ? "ENABLED" : "DISABLED") + "\n";
131 retval += "[AUTO BACKUP]: Interval: " + IntervalMinutes + " minutes" + "\n";
132 retval += "[AUTO BACKUP]: Do Busy Check: " + (BusyCheck ? "Yes" : "No") + "\n";
133 retval += "[AUTO BACKUP]: Naming Type: " + NamingType.ToString() + "\n"; 85 retval += "[AUTO BACKUP]: Naming Type: " + NamingType.ToString() + "\n";
134 retval += "[AUTO BACKUP]: Backup Dir: " + BackupDir + "\n";
135 retval += "[AUTO BACKUP]: Script: " + Script + "\n"; 86 retval += "[AUTO BACKUP]: Script: " + Script + "\n";
136 return retval; 87 return retval;
137 } 88 }
138 } 89 }
139} 90}
140
diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
index 5f47810..f378921 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
65 /// </summary> 65 /// </summary>
66 // private UUID EconomyBaseAccount = UUID.Zero; 66 // private UUID EconomyBaseAccount = UUID.Zero;
67 67
68 private float EnergyEfficiency = 0f; 68 private float EnergyEfficiency = 1f;
69 // private ObjectPaid handerOnObjectPaid; 69 // private ObjectPaid handerOnObjectPaid;
70 private bool m_enabled = true; 70 private bool m_enabled = true;
71 private bool m_sellEnabled = false; 71 private bool m_sellEnabled = true;
72 72
73 private IConfigSource m_gConfig; 73 private IConfigSource m_gConfig;
74 74
@@ -85,12 +85,12 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
85 85
86 private int ObjectCount = 0; 86 private int ObjectCount = 0;
87 private int PriceEnergyUnit = 0; 87 private int PriceEnergyUnit = 0;
88 private int PriceGroupCreate = 0; 88 private int PriceGroupCreate = -1;
89 private int PriceObjectClaim = 0; 89 private int PriceObjectClaim = 0;
90 private float PriceObjectRent = 0f; 90 private float PriceObjectRent = 0f;
91 private float PriceObjectScaleFactor = 0f; 91 private float PriceObjectScaleFactor = 10f;
92 private int PriceParcelClaim = 0; 92 private int PriceParcelClaim = 0;
93 private float PriceParcelClaimFactor = 0f; 93 private float PriceParcelClaimFactor = 1f;
94 private int PriceParcelRent = 0; 94 private int PriceParcelRent = 0;
95 private int PricePublicObjectDecay = 0; 95 private int PricePublicObjectDecay = 0;
96 private int PricePublicObjectDelete = 0; 96 private int PricePublicObjectDelete = 0;
@@ -98,7 +98,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
98 private int PriceUpload = 0; 98 private int PriceUpload = 0;
99 private int TeleportMinPrice = 0; 99 private int TeleportMinPrice = 0;
100 100
101 private float TeleportPriceExponent = 0f; 101 private float TeleportPriceExponent = 2f;
102 102
103 103
104 #region IMoneyModule Members 104 #region IMoneyModule Members
@@ -124,13 +124,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
124 public void Initialise(IConfigSource config) 124 public void Initialise(IConfigSource config)
125 { 125 {
126 m_gConfig = config; 126 m_gConfig = config;
127 127 ReadConfigAndPopulate();
128 IConfig startupConfig = m_gConfig.Configs["Startup"];
129 IConfig economyConfig = m_gConfig.Configs["Economy"];
130
131
132 ReadConfigAndPopulate(startupConfig, "Startup");
133 ReadConfigAndPopulate(economyConfig, "Economy");
134 } 128 }
135 129
136 public void AddRegion(Scene scene) 130 public void AddRegion(Scene scene)
@@ -151,13 +145,13 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
151 // to the command line parameters you use to start up your client 145 // to the command line parameters you use to start up your client
152 // This commonly looks like -helperuri http://127.0.0.1:9000/ 146 // This commonly looks like -helperuri http://127.0.0.1:9000/
153 147
154 148
155 // Local Server.. enables functionality only. 149 // Local Server.. enables functionality only.
156 httpServer.AddXmlRPCHandler("getCurrencyQuote", quote_func); 150 httpServer.AddXmlRPCHandler("getCurrencyQuote", quote_func);
157 httpServer.AddXmlRPCHandler("buyCurrency", buy_func); 151 httpServer.AddXmlRPCHandler("buyCurrency", buy_func);
158 httpServer.AddXmlRPCHandler("preflightBuyLandPrep", preflightBuyLandPrep_func); 152 httpServer.AddXmlRPCHandler("preflightBuyLandPrep", preflightBuyLandPrep_func);
159 httpServer.AddXmlRPCHandler("buyLandPrep", landBuy_func); 153 httpServer.AddXmlRPCHandler("buyLandPrep", landBuy_func);
160 154
161 } 155 }
162 156
163 if (m_scenel.ContainsKey(scene.RegionInfo.RegionHandle)) 157 if (m_scenel.ContainsKey(scene.RegionInfo.RegionHandle))
@@ -205,13 +199,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
205 { 199 {
206 } 200 }
207 201
208 public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount) 202 public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount, UUID txn, out string result)
209 { 203 {
204 result = String.Empty;
210 string description = String.Format("Object {0} pays {1}", resolveObjectName(objectID), resolveAgentName(toID)); 205 string description = String.Format("Object {0} pays {1}", resolveObjectName(objectID), resolveAgentName(toID));
211 206
212 bool give_result = doMoneyTransfer(fromID, toID, amount, 2, description); 207 bool give_result = doMoneyTransfer(fromID, toID, amount, 2, description);
213 208
214 209
215 BalanceUpdate(fromID, toID, give_result, description); 210 BalanceUpdate(fromID, toID, give_result, description);
216 211
217 return give_result; 212 return give_result;
@@ -240,35 +235,51 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
240 /// <summary> 235 /// <summary>
241 /// Parse Configuration 236 /// Parse Configuration
242 /// </summary> 237 /// </summary>
243 /// <param name="scene"></param> 238 private void ReadConfigAndPopulate()
244 /// <param name="startupConfig"></param>
245 /// <param name="config"></param>
246 private void ReadConfigAndPopulate(IConfig startupConfig, string config)
247 { 239 {
248 if (config == "Startup" && startupConfig != null) 240 // we are enabled by default
241
242 IConfig startupConfig = m_gConfig.Configs["Startup"];
243
244 if(startupConfig == null) // should not happen
245 return;
246
247 IConfig economyConfig = m_gConfig.Configs["Economy"];
248
249 // economymodule may be at startup or Economy (legacy)
250 string mmodule = startupConfig.GetString("economymodule","");
251 if(String.IsNullOrEmpty(mmodule))
249 { 252 {
250 m_enabled = (startupConfig.GetString("economymodule", "BetaGridLikeMoneyModule") == "BetaGridLikeMoneyModule"); 253 if(economyConfig != null)
254 mmodule = economyConfig.GetString("economymodule","");
251 } 255 }
252 256
253 if (config == "Economy" && startupConfig != null) 257 if(!String.IsNullOrEmpty(mmodule) && mmodule != Name)
254 { 258 {
255 PriceEnergyUnit = startupConfig.GetInt("PriceEnergyUnit", 100); 259 // some other money module selected
256 PriceObjectClaim = startupConfig.GetInt("PriceObjectClaim", 10); 260 m_enabled = false;
257 PricePublicObjectDecay = startupConfig.GetInt("PricePublicObjectDecay", 4); 261 return;
258 PricePublicObjectDelete = startupConfig.GetInt("PricePublicObjectDelete", 4);
259 PriceParcelClaim = startupConfig.GetInt("PriceParcelClaim", 1);
260 PriceParcelClaimFactor = startupConfig.GetFloat("PriceParcelClaimFactor", 1f);
261 PriceUpload = startupConfig.GetInt("PriceUpload", 0);
262 PriceRentLight = startupConfig.GetInt("PriceRentLight", 5);
263 TeleportMinPrice = startupConfig.GetInt("TeleportMinPrice", 2);
264 TeleportPriceExponent = startupConfig.GetFloat("TeleportPriceExponent", 2f);
265 EnergyEfficiency = startupConfig.GetFloat("EnergyEfficiency", 1);
266 PriceObjectRent = startupConfig.GetFloat("PriceObjectRent", 1);
267 PriceObjectScaleFactor = startupConfig.GetFloat("PriceObjectScaleFactor", 10);
268 PriceParcelRent = startupConfig.GetInt("PriceParcelRent", 1);
269 PriceGroupCreate = startupConfig.GetInt("PriceGroupCreate", -1);
270 m_sellEnabled = startupConfig.GetBoolean("SellEnabled", false);
271 } 262 }
263
264 if(economyConfig == null)
265 return;
266
267 PriceEnergyUnit = economyConfig.GetInt("PriceEnergyUnit", 0);
268 PriceObjectClaim = economyConfig.GetInt("PriceObjectClaim", 0);
269 PricePublicObjectDecay = economyConfig.GetInt("PricePublicObjectDecay", 4);
270 PricePublicObjectDelete = economyConfig.GetInt("PricePublicObjectDelete", 0);
271 PriceParcelClaim = economyConfig.GetInt("PriceParcelClaim", 0);
272 PriceParcelClaimFactor = economyConfig.GetFloat("PriceParcelClaimFactor", 1f);
273 PriceUpload = economyConfig.GetInt("PriceUpload", 0);
274 PriceRentLight = economyConfig.GetInt("PriceRentLight", 0);
275 TeleportMinPrice = economyConfig.GetInt("TeleportMinPrice", 0);
276 TeleportPriceExponent = economyConfig.GetFloat("TeleportPriceExponent", 2f);
277 EnergyEfficiency = economyConfig.GetFloat("EnergyEfficiency", 1);
278 PriceObjectRent = economyConfig.GetFloat("PriceObjectRent", 0);
279 PriceObjectScaleFactor = economyConfig.GetFloat("PriceObjectScaleFactor", 10);
280 PriceParcelRent = economyConfig.GetInt("PriceParcelRent", 0);
281 PriceGroupCreate = economyConfig.GetInt("PriceGroupCreate", -1);
282 m_sellEnabled = economyConfig.GetBoolean("SellEnabled", true);
272 } 283 }
273 284
274 private void GetClientFunds(IClientAPI client) 285 private void GetClientFunds(IClientAPI client)
@@ -302,7 +313,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
302 private bool doMoneyTransfer(UUID Sender, UUID Receiver, int amount, int transactiontype, string description) 313 private bool doMoneyTransfer(UUID Sender, UUID Receiver, int amount, int transactiontype, string description)
303 { 314 {
304 bool result = true; 315 bool result = true;
305 316
306 return result; 317 return result;
307 } 318 }
308 319
@@ -376,10 +387,10 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
376 else 387 else
377 { 388 {
378 m_log.ErrorFormat( 389 m_log.ErrorFormat(
379 "[MONEY]: Could not resolve user {0}", 390 "[MONEY]: Could not resolve user {0}",
380 agentID); 391 agentID);
381 } 392 }
382 393
383 return String.Empty; 394 return String.Empty;
384 } 395 }
385 396
@@ -463,7 +474,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
463 Hashtable quoteResponse = new Hashtable(); 474 Hashtable quoteResponse = new Hashtable();
464 XmlRpcResponse returnval = new XmlRpcResponse(); 475 XmlRpcResponse returnval = new XmlRpcResponse();
465 476
466 477
467 Hashtable currencyResponse = new Hashtable(); 478 Hashtable currencyResponse = new Hashtable();
468 currencyResponse.Add("estimatedCost", 0); 479 currencyResponse.Add("estimatedCost", 0);
469 currencyResponse.Add("currencyBuy", amount); 480 currencyResponse.Add("currencyBuy", amount);
@@ -474,7 +485,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
474 485
475 returnval.Value = quoteResponse; 486 returnval.Value = quoteResponse;
476 return returnval; 487 return returnval;
477 488
478 489
479 490
480 } 491 }
@@ -484,7 +495,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
484 // Hashtable requestData = (Hashtable) request.Params[0]; 495 // Hashtable requestData = (Hashtable) request.Params[0];
485 // UUID agentId = UUID.Zero; 496 // UUID agentId = UUID.Zero;
486 // int amount = 0; 497 // int amount = 0;
487 498
488 XmlRpcResponse returnval = new XmlRpcResponse(); 499 XmlRpcResponse returnval = new XmlRpcResponse();
489 Hashtable returnresp = new Hashtable(); 500 Hashtable returnresp = new Hashtable();
490 returnresp.Add("success", true); 501 returnresp.Add("success", true);
@@ -535,7 +546,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
535 546
536 // UUID agentId = UUID.Zero; 547 // UUID agentId = UUID.Zero;
537 // int amount = 0; 548 // int amount = 0;
538 549
539 retparam.Add("success", true); 550 retparam.Add("success", true);
540 ret.Value = retparam; 551 ret.Value = retparam;
541 552
@@ -552,7 +563,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
552 /// <param name="agentID"></param> 563 /// <param name="agentID"></param>
553 private void CheckExistAndRefreshFunds(UUID agentID) 564 private void CheckExistAndRefreshFunds(UUID agentID)
554 { 565 {
555 566
556 } 567 }
557 568
558 /// <summary> 569 /// <summary>
@@ -562,14 +573,23 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
562 /// <returns></returns> 573 /// <returns></returns>
563 private int GetFundsForAgentID(UUID AgentID) 574 private int GetFundsForAgentID(UUID AgentID)
564 { 575 {
565 int returnfunds = 82101; // Set it to the OpenSim version, plus the IG build number. Muahahaha; 576 int result = 0;
566 577 // Set it to the OpenSim version, plus the SC build number. Muahahaha;
567 return returnfunds; 578 string v = VersionInfo.VersionNumber + VersionInfo.SC_BUILD_NUMBER.PadLeft(3, '0');
579 try
580 {
581 result = Int32.Parse(v.Replace(".", ""));
582 }
583 catch (FormatException)
584 {
585 }
586
587 return result;
568 } 588 }
569 589
570 // private void SetLocalFundsForAgentID(UUID AgentID, int amount) 590 // private void SetLocalFundsForAgentID(UUID AgentID, int amount)
571 // { 591 // {
572 592
573 // } 593 // }
574 594
575 #endregion 595 #endregion
@@ -688,7 +708,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
688 /// <see cref="OpenSim.Region.Framework.Scenes.EventManager.ClientClosed"/> 708 /// <see cref="OpenSim.Region.Framework.Scenes.EventManager.ClientClosed"/>
689 public void ClientClosed(UUID AgentID, Scene scene) 709 public void ClientClosed(UUID AgentID, Scene scene)
690 { 710 {
691 711
692 } 712 }
693 713
694 /// <summary> 714 /// <summary>
@@ -707,19 +727,19 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
707 727
708 private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e) 728 private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e)
709 { 729 {
710 730
711 731
712 lock (e) 732 lock (e)
713 { 733 {
714 e.economyValidated = true; 734 e.economyValidated = true;
715 } 735 }
716 736
717 737
718 } 738 }
719 739
720 private void processLandBuy(Object osender, EventManager.LandBuyArgs e) 740 private void processLandBuy(Object osender, EventManager.LandBuyArgs e)
721 { 741 {
722 742
723 } 743 }
724 744
725 /// <summary> 745 /// <summary>
@@ -729,7 +749,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
729 /// <param name="e"></param> 749 /// <param name="e"></param>
730 private void MoneyTransferAction(Object osender, EventManager.MoneyTransferArgs e) 750 private void MoneyTransferAction(Object osender, EventManager.MoneyTransferArgs e)
731 { 751 {
732 752
733 } 753 }
734 754
735 /// <summary> 755 /// <summary>
@@ -738,7 +758,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
738 /// <param name="avatar"></param> 758 /// <param name="avatar"></param>
739 private void MakeChildAgent(ScenePresence avatar) 759 private void MakeChildAgent(ScenePresence avatar)
740 { 760 {
741 761
742 } 762 }
743 763
744 /// <summary> 764 /// <summary>
@@ -747,7 +767,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
747 /// <param name="AgentId"></param> 767 /// <param name="AgentId"></param>
748 private void ClientLoggedOut(UUID AgentId, Scene scene) 768 private void ClientLoggedOut(UUID AgentId, Scene scene)
749 { 769 {
750 770
751 } 771 }
752 772
753 /// <summary> 773 /// <summary>
@@ -767,7 +787,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
767 /// <param name="regionID"></param> 787 /// <param name="regionID"></param>
768 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID) 788 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
769 { 789 {
770 790
771 //m_log.Info("[FRIEND]: " + avatar.Name + " status:" + (!avatar.IsChildAgent).ToString()); 791 //m_log.Info("[FRIEND]: " + avatar.Name + " status:" + (!avatar.IsChildAgent).ToString());
772 } 792 }
773 793
@@ -808,12 +828,12 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
808 828
809 Scene s = LocateSceneClientIn(remoteClient.AgentId); 829 Scene s = LocateSceneClientIn(remoteClient.AgentId);
810 830
811 // Implmenting base sale data checking here so the default OpenSimulator implementation isn't useless 831 // Implmenting base sale data checking here so the default OpenSimulator implementation isn't useless
812 // combined with other implementations. We're actually validating that the client is sending the data 832 // combined with other implementations. We're actually validating that the client is sending the data
813 // that it should. In theory, the client should already know what to send here because it'll see it when it 833 // that it should. In theory, the client should already know what to send here because it'll see it when it
814 // gets the object data. If the data sent by the client doesn't match the object, the viewer probably has an 834 // gets the object data. If the data sent by the client doesn't match the object, the viewer probably has an
815 // old idea of what the object properties are. Viewer developer Hazim informed us that the base module 835 // old idea of what the object properties are. Viewer developer Hazim informed us that the base module
816 // didn't check the client sent data against the object do any. Since the base modules are the 836 // didn't check the client sent data against the object do any. Since the base modules are the
817 // 'crowning glory' examples of good practice.. 837 // 'crowning glory' examples of good practice..
818 838
819 // Validate that the object exists in the scene the user is in 839 // Validate that the object exists in the scene the user is in
@@ -823,15 +843,15 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
823 remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found.", false); 843 remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found.", false);
824 return; 844 return;
825 } 845 }
826 846
827 // Validate that the client sent the price that the object is being sold for 847 // Validate that the client sent the price that the object is being sold for
828 if (part.SalePrice != salePrice) 848 if (part.SalePrice != salePrice)
829 { 849 {
830 remoteClient.SendAgentAlertMessage("Cannot buy at this price. Buy Failed. If you continue to get this relog.", false); 850 remoteClient.SendAgentAlertMessage("Cannot buy at this price. Buy Failed. If you continue to get this relog.", false);
831 return; 851 return;
832 } 852 }
833 853
834 // Validate that the client sent the proper sale type the object has set 854 // Validate that the client sent the proper sale type the object has set
835 if (part.ObjectSaleType != saleType) 855 if (part.ObjectSaleType != saleType)
836 { 856 {
837 remoteClient.SendAgentAlertMessage("Cannot buy this way. Buy Failed. If you continue to get this relog.", false); 857 remoteClient.SendAgentAlertMessage("Cannot buy this way. Buy Failed. If you continue to get this relog.", false);
@@ -842,6 +862,15 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
842 if (module != null) 862 if (module != null)
843 module.BuyObject(remoteClient, categoryID, localID, saleType, salePrice); 863 module.BuyObject(remoteClient, categoryID, localID, saleType, salePrice);
844 } 864 }
865
866 public void MoveMoney(UUID fromUser, UUID toUser, int amount, string text)
867 {
868 }
869
870 public bool MoveMoney(UUID fromUser, UUID toUser, int amount, MoneyTransactionType type, string text)
871 {
872 return true;
873 }
845 } 874 }
846 875
847 public enum TransactionType : int 876 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
43 public class NPCAvatar : IClientAPI, INPC 43 public class NPCAvatar : IClientAPI, INPC
44 { 44 {
45 public bool SenseAsAgent { get; set; } 45 public bool SenseAsAgent { get; set; }
46 public UUID Owner
47 {
48 get { return m_ownerID;}
49 }
46 50
47 public delegate void ChatToNPC( 51 public delegate void ChatToNPC(
48 string message, byte type, Vector3 fromPos, string fromName, 52 string message, byte type, Vector3 fromPos, string fromName,
49 UUID fromAgentID, UUID ownerID, byte source, byte audible); 53 UUID fromAgentID, UUID ownerID, byte source, byte audible);
50 54
51 /// <summary> 55 /// <summary>
@@ -61,9 +65,14 @@ namespace OpenSim.Region.OptionalModules.World.NPC
61 private readonly string m_firstname; 65 private readonly string m_firstname;
62 private readonly string m_lastname; 66 private readonly string m_lastname;
63 private readonly Vector3 m_startPos; 67 private readonly Vector3 m_startPos;
64 private readonly UUID m_uuid; 68 private UUID m_uuid = UUID.Random();
65 private readonly Scene m_scene; 69 private readonly Scene m_scene;
66 private readonly UUID m_ownerID; 70 private readonly UUID m_ownerID;
71 private UUID m_hostGroupID;
72 private string m_profileAbout = "";
73 private UUID m_profileImage = UUID.Zero;
74 private string m_born;
75 public List<uint> SelectedObjects {get; private set;}
67 76
68 public NPCAvatar( 77 public NPCAvatar(
69 string firstname, string lastname, Vector3 position, UUID ownerID, bool senseAsAgent, Scene scene) 78 string firstname, string lastname, Vector3 position, UUID ownerID, bool senseAsAgent, Scene scene)
@@ -75,6 +84,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
75 m_scene = scene; 84 m_scene = scene;
76 m_ownerID = ownerID; 85 m_ownerID = ownerID;
77 SenseAsAgent = senseAsAgent; 86 SenseAsAgent = senseAsAgent;
87 m_hostGroupID = UUID.Zero;
78 } 88 }
79 89
80 public NPCAvatar( 90 public NPCAvatar(
@@ -87,6 +97,25 @@ namespace OpenSim.Region.OptionalModules.World.NPC
87 m_scene = scene; 97 m_scene = scene;
88 m_ownerID = ownerID; 98 m_ownerID = ownerID;
89 SenseAsAgent = senseAsAgent; 99 SenseAsAgent = senseAsAgent;
100 m_hostGroupID = UUID.Zero;
101 }
102
103 public string profileAbout
104 {
105 get { return m_profileAbout; }
106 set
107 {
108 if(value.Length > 255)
109 m_profileAbout = value.Substring(0,255);
110 else
111 m_profileAbout = value;
112 }
113 }
114
115 public UUID profileImage
116 {
117 get { return m_profileImage; }
118 set { m_profileImage = value; }
90 } 119 }
91 120
92 public IScene Scene 121 public IScene Scene
@@ -94,6 +123,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC
94 get { return m_scene; } 123 get { return m_scene; }
95 } 124 }
96 125
126 public int PingTimeMS { get { return 0; } }
127
97 public UUID OwnerID 128 public UUID OwnerID
98 { 129 {
99 get { return m_ownerID; } 130 get { return m_ownerID; }
@@ -187,9 +218,15 @@ namespace OpenSim.Region.OptionalModules.World.NPC
187 { 218 {
188 219
189 } 220 }
190 221
191 public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, Quaternion SitOrientation, bool autopilot, 222 public void SendFindAgent(UUID HunterID, UUID PreyID, double GlobalX, double GlobalY)
192 Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) 223 {
224
225 }
226
227 public void SendSitResponse(UUID TargetID, Vector3 OffsetPos,
228 Quaternion SitOrientation, bool autopilot,
229 Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook)
193 { 230 {
194 231
195 } 232 }
@@ -248,7 +285,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
248#pragma warning disable 67 285#pragma warning disable 67
249 public event Action<IClientAPI> OnLogout; 286 public event Action<IClientAPI> OnLogout;
250 public event ObjectPermissions OnObjectPermissions; 287 public event ObjectPermissions OnObjectPermissions;
251 288 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
252 public event MoneyTransferRequest OnMoneyTransferRequest; 289 public event MoneyTransferRequest OnMoneyTransferRequest;
253 public event ParcelBuy OnParcelBuy; 290 public event ParcelBuy OnParcelBuy;
254 public event Action<IClientAPI> OnConnectionClosed; 291 public event Action<IClientAPI> OnConnectionClosed;
@@ -268,6 +305,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
268 public event ObjectDrop OnObjectDrop; 305 public event ObjectDrop OnObjectDrop;
269 public event StartAnim OnStartAnim; 306 public event StartAnim OnStartAnim;
270 public event StopAnim OnStopAnim; 307 public event StopAnim OnStopAnim;
308 public event ChangeAnim OnChangeAnim;
271 public event LinkObjects OnLinkObjects; 309 public event LinkObjects OnLinkObjects;
272 public event DelinkObjects OnDelinkObjects; 310 public event DelinkObjects OnDelinkObjects;
273 public event RequestMapBlocks OnRequestMapBlocks; 311 public event RequestMapBlocks OnRequestMapBlocks;
@@ -280,6 +318,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
280 public event SetAlwaysRun OnSetAlwaysRun; 318 public event SetAlwaysRun OnSetAlwaysRun;
281 319
282 public event DeRezObject OnDeRezObject; 320 public event DeRezObject OnDeRezObject;
321 public event RezRestoreToWorld OnRezRestoreToWorld;
283 public event Action<IClientAPI> OnRegionHandShakeReply; 322 public event Action<IClientAPI> OnRegionHandShakeReply;
284 public event GenericCall1 OnRequestWearables; 323 public event GenericCall1 OnRequestWearables;
285 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 324 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
@@ -318,6 +357,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
318 public event UpdatePrimTexture OnUpdatePrimTexture; 357 public event UpdatePrimTexture OnUpdatePrimTexture;
319 public event UpdateVector OnUpdatePrimGroupPosition; 358 public event UpdateVector OnUpdatePrimGroupPosition;
320 public event UpdateVector OnUpdatePrimSinglePosition; 359 public event UpdateVector OnUpdatePrimSinglePosition;
360 public event ClientChangeObject onClientChangeObject;
321 public event UpdatePrimRotation OnUpdatePrimGroupRotation; 361 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
322 public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; 362 public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition;
323 public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; 363 public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation;
@@ -456,7 +496,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
456 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 496 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
457 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 497 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
458 public event ClassifiedDelete OnClassifiedDelete; 498 public event ClassifiedDelete OnClassifiedDelete;
459 public event ClassifiedDelete OnClassifiedGodDelete; 499 public event ClassifiedGodDelete OnClassifiedGodDelete;
460 500
461 public event EventNotificationAddRequest OnEventNotificationAddRequest; 501 public event EventNotificationAddRequest OnEventNotificationAddRequest;
462 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 502 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
@@ -479,7 +519,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
479 public event AvatarInterestUpdate OnAvatarInterestUpdate; 519 public event AvatarInterestUpdate OnAvatarInterestUpdate;
480 520
481 public event PlacesQuery OnPlacesQuery; 521 public event PlacesQuery OnPlacesQuery;
482 522
483 public event FindAgentUpdate OnFindAgent; 523 public event FindAgentUpdate OnFindAgent;
484 public event TrackAgentUpdate OnTrackAgent; 524 public event TrackAgentUpdate OnTrackAgent;
485 public event NewUserReport OnUserReport; 525 public event NewUserReport OnUserReport;
@@ -495,11 +535,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC
495 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 535 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
496 public event SimWideDeletesDelegate OnSimWideDeletes; 536 public event SimWideDeletesDelegate OnSimWideDeletes;
497 public event SendPostcard OnSendPostcard; 537 public event SendPostcard OnSendPostcard;
538 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
498 public event MuteListEntryUpdate OnUpdateMuteListEntry; 539 public event MuteListEntryUpdate OnUpdateMuteListEntry;
499 public event MuteListEntryRemove OnRemoveMuteListEntry; 540 public event MuteListEntryRemove OnRemoveMuteListEntry;
500 public event GodlikeMessage onGodlikeMessage; 541 public event GodlikeMessage onGodlikeMessage;
501 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 542 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
502 543 public event GenericCall2 OnUpdateThrottles;
503#pragma warning restore 67 544#pragma warning restore 67
504 545
505 #endregion 546 #endregion
@@ -522,6 +563,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
522 public virtual UUID AgentId 563 public virtual UUID AgentId
523 { 564 {
524 get { return m_uuid; } 565 get { return m_uuid; }
566 set { m_uuid = value; }
525 } 567 }
526 568
527 public UUID SessionId 569 public UUID SessionId
@@ -562,24 +604,40 @@ namespace OpenSim.Region.OptionalModules.World.NPC
562 } 604 }
563 public UUID ActiveGroupId 605 public UUID ActiveGroupId
564 { 606 {
565 get { return UUID.Zero; } 607 get { return m_hostGroupID; }
608 set { m_hostGroupID = value; }
566 } 609 }
567 610
568 public string ActiveGroupName 611 public string ActiveGroupName
569 { 612 {
570 get { return String.Empty; } 613 get { return String.Empty; }
614 set { }
571 } 615 }
572 616
573 public ulong ActiveGroupPowers 617 public ulong ActiveGroupPowers
574 { 618 {
575 get { return 0; } 619 get { return 0; }
620 set { }
621 }
622
623 public string Born
624 {
625 get { return m_born; }
626 set { m_born = value; }
576 } 627 }
577 628
578 public bool IsGroupMember(UUID groupID) 629 public bool IsGroupMember(UUID groupID)
579 { 630 {
580 return false; 631 return (m_hostGroupID == groupID);
632 }
633
634 public Dictionary<UUID, ulong> GetGroupPowers()
635 {
636 return new Dictionary<UUID, ulong>();
581 } 637 }
582 638
639 public void SetGroupPowers(Dictionary<UUID, ulong> powers) { }
640
583 public ulong GetGroupPowers(UUID groupID) 641 public ulong GetGroupPowers(UUID groupID)
584 { 642 {
585 return 0; 643 return 0;
@@ -627,6 +685,17 @@ namespace OpenSim.Region.OptionalModules.World.NPC
627 public virtual void SetChildAgentThrottle(byte[] throttle) 685 public virtual void SetChildAgentThrottle(byte[] throttle)
628 { 686 {
629 } 687 }
688
689 public virtual void SetChildAgentThrottle(byte[] throttle, float factor)
690 {
691
692 }
693
694 public void SetAgentThrottleSilent(int throttle, int setting)
695 {
696
697
698 }
630 public byte[] GetThrottlesPacked(float multiplier) 699 public byte[] GetThrottlesPacked(float multiplier)
631 { 700 {
632 return new byte[0]; 701 return new byte[0];
@@ -665,6 +734,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC
665 734
666 } 735 }
667 736
737 public virtual bool CanSendLayerData()
738 {
739 return false;
740 }
741
668 public virtual void SendLayerData(float[] map) 742 public virtual void SendLayerData(float[] map)
669 { 743 {
670 } 744 }
@@ -676,9 +750,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC
676 { 750 {
677 } 751 }
678 752
679 public virtual void SendWindData(Vector2[] windSpeeds) { } 753 public virtual void SendWindData(int version, Vector2[] windSpeeds) { }
680 754
681 public virtual void SendCloudData(float[] cloudCover) { } 755 public virtual void SendCloudData(int version, float[] cloudCover) { }
682 756
683 public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 757 public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
684 { 758 {
@@ -739,7 +813,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC
739 { 813 {
740 } 814 }
741 815
742 public void SendAvatarDataImmediate(ISceneEntity avatar) 816 public void SendEntityFullUpdateImmediate(ISceneEntity avatar)
817 {
818 }
819
820 public void SendEntityTerseUpdateImmediate(ISceneEntity ent)
743 { 821 {
744 } 822 }
745 823
@@ -772,6 +850,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC
772 { 850 {
773 } 851 }
774 852
853 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
854 {
855 }
856
775 public virtual void SendRemoveInventoryItem(UUID itemID) 857 public virtual void SendRemoveInventoryItem(UUID itemID)
776 { 858 {
777 } 859 }
@@ -788,7 +870,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
788 { 870 {
789 } 871 }
790 872
791 public virtual void SendXferPacket(ulong xferID, uint packet, byte[] data) 873 public virtual void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
792 { 874 {
793 } 875 }
794 public virtual void SendAbortXferPacket(ulong xferID) 876 public virtual void SendAbortXferPacket(ulong xferID)
@@ -833,6 +915,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC
833 { 915 {
834 } 916 }
835 917
918 public void SendAlertMessage(string message, string info)
919 {
920 }
921
836 public void SendSystemAlertMessage(string message) 922 public void SendSystemAlertMessage(string message)
837 { 923 {
838 } 924 }
@@ -849,7 +935,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
849 OnRegionHandShakeReply(this); 935 OnRegionHandShakeReply(this);
850 } 936 }
851 } 937 }
852 938
853 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 939 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
854 { 940 {
855 } 941 }
@@ -869,7 +955,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
869 public void SendImageFirstPart(ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec) 955 public void SendImageFirstPart(ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec)
870 { 956 {
871 } 957 }
872 958
873 public void SendImageNotFound(UUID imageid) 959 public void SendImageNotFound(UUID imageid)
874 { 960 {
875 } 961 }
@@ -877,7 +963,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
877 public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData) 963 public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData)
878 { 964 {
879 } 965 }
880 966
881 public void SendShutdownConnectionNotice() 967 public void SendShutdownConnectionNotice()
882 { 968 {
883 } 969 }
@@ -888,7 +974,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
888 974
889 public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) 975 public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
890 { 976 {
891 977
892 } 978 }
893 979
894 public void SendObjectPropertiesReply(ISceneEntity entity) 980 public void SendObjectPropertiesReply(ISceneEntity entity)
@@ -902,12 +988,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC
902 public void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks) 988 public void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks)
903 { 989 {
904 } 990 }
905 991
906 public void SendViewerTime(int phase) 992 public void SendViewerTime(int phase)
907 { 993 {
908 } 994 }
909 995
910 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, 996 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType,
911 string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, 997 string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL,
912 UUID partnerID) 998 UUID partnerID)
913 { 999 {
@@ -933,10 +1019,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC
933 1019
934 public void Close() 1020 public void Close()
935 { 1021 {
936 Close(false); 1022 Close(true, false);
937 } 1023 }
938 1024
939 public void Close(bool force) 1025 public void Close(bool sendStop, bool force)
940 { 1026 {
941 // Remove ourselves from the scene 1027 // Remove ourselves from the scene
942 m_scene.RemoveClient(AgentId, false); 1028 m_scene.RemoveClient(AgentId, false);
@@ -947,7 +1033,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
947 // We never start the client, so always fail. 1033 // We never start the client, so always fail.
948 throw new NotImplementedException(); 1034 throw new NotImplementedException();
949 } 1035 }
950 1036
951 public void Stop() 1037 public void Stop()
952 { 1038 {
953 } 1039 }
@@ -1142,11 +1228,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC
1142 public void SendJoinGroupReply(UUID groupID, bool success) 1228 public void SendJoinGroupReply(UUID groupID, bool success)
1143 { 1229 {
1144 } 1230 }
1145 1231
1146 public void SendEjectGroupMemberReply(UUID agentID, UUID groupID, bool success) 1232 public void SendEjectGroupMemberReply(UUID agentID, UUID groupID, bool success)
1147 { 1233 {
1148 } 1234 }
1149 1235
1150 public void SendLeaveGroupReply(UUID groupID, bool success) 1236 public void SendLeaveGroupReply(UUID groupID, bool success)
1151 { 1237 {
1152 } 1238 }
@@ -1155,6 +1241,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC
1155 { 1241 {
1156 } 1242 }
1157 1243
1244 public void SendAgentGroupDataUpdate(UUID avatarID, GroupMembershipData[] data)
1245 {
1246 }
1247
1158 public void SendTerminateFriend(UUID exFriendID) 1248 public void SendTerminateFriend(UUID exFriendID)
1159 { 1249 {
1160 } 1250 }
@@ -1208,10 +1298,26 @@ namespace OpenSim.Region.OptionalModules.World.NPC
1208 { 1298 {
1209 } 1299 }
1210 1300
1301 public void UpdateGroupMembership(GroupMembershipData[] data)
1302 {
1303 }
1304
1305 public void GroupMembershipRemove(UUID GroupID)
1306 {
1307 }
1308
1309 public void GroupMembershipAddReplace(UUID GroupID,ulong GroupPowers)
1310 {
1311 }
1312
1211 public void SendUseCachedMuteList() 1313 public void SendUseCachedMuteList()
1212 { 1314 {
1213 } 1315 }
1214 1316
1317 public void SendEmpytMuteList()
1318 {
1319 }
1320
1215 public void SendMuteListUpdate(string filename) 1321 public void SendMuteListUpdate(string filename)
1216 { 1322 {
1217 } 1323 }
@@ -1220,7 +1326,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
1220 { 1326 {
1221 } 1327 }
1222 #endregion 1328 #endregion
1223 1329
1224 public void SendRebakeAvatarTextures(UUID textureID) 1330 public void SendRebakeAvatarTextures(UUID textureID)
1225 { 1331 {
1226 } 1332 }
@@ -1228,15 +1334,15 @@ namespace OpenSim.Region.OptionalModules.World.NPC
1228 public void SendAvatarInterestsReply(UUID avatarID, uint wantMask, string wantText, uint skillsMask, string skillsText, string languages) 1334 public void SendAvatarInterestsReply(UUID avatarID, uint wantMask, string wantText, uint skillsMask, string skillsText, string languages)
1229 { 1335 {
1230 } 1336 }
1231 1337
1232 public void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt) 1338 public void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt)
1233 { 1339 {
1234 } 1340 }
1235 1341
1236 public void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier) 1342 public void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier)
1237 { 1343 {
1238 } 1344 }
1239 1345
1240 public void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID,int amt) 1346 public void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID,int amt)
1241 { 1347 {
1242 } 1348 }
@@ -1256,7 +1362,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
1256 public void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId) 1362 public void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId)
1257 { 1363 {
1258 } 1364 }
1259 1365
1260 public void SendAgentTerseUpdate(ISceneEntity presence) 1366 public void SendAgentTerseUpdate(ISceneEntity presence)
1261 { 1367 {
1262 } 1368 }
@@ -1265,9 +1371,22 @@ namespace OpenSim.Region.OptionalModules.World.NPC
1265 { 1371 {
1266 } 1372 }
1267 1373
1374 public void SendSelectedPartsProprieties(List<ISceneEntity> parts)
1375 {
1376 }
1377
1268 public void SendPartPhysicsProprieties(ISceneEntity entity) 1378 public void SendPartPhysicsProprieties(ISceneEntity entity)
1269 { 1379 {
1270 } 1380 }
1271 1381
1382 public void SendPartFullUpdate(ISceneEntity ent, uint? parentID)
1383 {
1384 }
1385
1386 public int GetAgentThrottleSilent(int throttle)
1387 {
1388 return 0;
1389 }
1390
1272 } 1391 }
1273} 1392}
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
52 private Dictionary<UUID, NPCAvatar> m_avatars = 52 private Dictionary<UUID, NPCAvatar> m_avatars =
53 new Dictionary<UUID, NPCAvatar>(); 53 new Dictionary<UUID, NPCAvatar>();
54 54
55
56
57 private NPCOptionsFlags m_NPCOptionFlags;
58 public NPCOptionsFlags NPCOptionFlags {get {return m_NPCOptionFlags;}}
59
55 public bool Enabled { get; private set; } 60 public bool Enabled { get; private set; }
56 61
57 public void Initialise(IConfigSource source) 62 public void Initialise(IConfigSource source)
@@ -59,6 +64,21 @@ namespace OpenSim.Region.OptionalModules.World.NPC
59 IConfig config = source.Configs["NPC"]; 64 IConfig config = source.Configs["NPC"];
60 65
61 Enabled = (config != null && config.GetBoolean("Enabled", false)); 66 Enabled = (config != null && config.GetBoolean("Enabled", false));
67 m_NPCOptionFlags = NPCOptionsFlags.None;
68 if(Enabled)
69 {
70 if(config.GetBoolean("AllowNotOwned", true))
71 m_NPCOptionFlags |= NPCOptionsFlags.AllowNotOwned;
72
73 if(config.GetBoolean("AllowSenseAsAvatar", true))
74 m_NPCOptionFlags |= NPCOptionsFlags.AllowSenseAsAvatar;
75
76 if(config.GetBoolean("AllowCloneOtherAvatars", true))
77 m_NPCOptionFlags |= NPCOptionsFlags.AllowCloneOtherAvatars;
78
79 if(config.GetBoolean("NoNPCGroup", true))
80 m_NPCOptionFlags |= NPCOptionsFlags.NoNPCGroup;
81 }
62 } 82 }
63 83
64 public void AddRegion(Scene scene) 84 public void AddRegion(Scene scene)
@@ -137,17 +157,18 @@ namespace OpenSim.Region.OptionalModules.World.NPC
137 } 157 }
138 158
139 public UUID CreateNPC(string firstname, string lastname, 159 public UUID CreateNPC(string firstname, string lastname,
140 Vector3 position, UUID owner, bool senseAsAgent, Scene scene, 160 Vector3 position, UUID owner, bool senseAsAgent, Scene scene,
141 AvatarAppearance appearance) 161 AvatarAppearance appearance)
142 { 162 {
143 return CreateNPC(firstname, lastname, position, UUID.Zero, owner, senseAsAgent, scene, appearance); 163 return CreateNPC(firstname, lastname, position, UUID.Zero, owner, "", UUID.Zero, senseAsAgent, scene, appearance);
144 } 164 }
145 165
146 public UUID CreateNPC(string firstname, string lastname, 166 public UUID CreateNPC(string firstname, string lastname,
147 Vector3 position, UUID agentID, UUID owner, bool senseAsAgent, Scene scene, 167 Vector3 position, UUID agentID, UUID owner, string groupTitle, UUID groupID, bool senseAsAgent, Scene scene,
148 AvatarAppearance appearance) 168 AvatarAppearance appearance)
149 { 169 {
150 NPCAvatar npcAvatar = null; 170 NPCAvatar npcAvatar = null;
171 string born = DateTime.UtcNow.ToString();
151 172
152 try 173 try
153 { 174 {
@@ -167,10 +188,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC
167 npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0, 188 npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0,
168 int.MaxValue); 189 int.MaxValue);
169 190
170 m_log.DebugFormat( 191// m_log.DebugFormat(
171 "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}", 192// "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}",
172 firstname, lastname, npcAvatar.AgentId, owner, 193// firstname, lastname, npcAvatar.AgentId, owner, senseAsAgent, position, scene.RegionInfo.RegionName);
173 senseAsAgent, position, scene.RegionInfo.RegionName);
174 194
175 AgentCircuitData acd = new AgentCircuitData(); 195 AgentCircuitData acd = new AgentCircuitData();
176 acd.AgentID = npcAvatar.AgentId; 196 acd.AgentID = npcAvatar.AgentId;
@@ -181,30 +201,44 @@ namespace OpenSim.Region.OptionalModules.World.NPC
181 AvatarAppearance npcAppearance = new AvatarAppearance(appearance, true); 201 AvatarAppearance npcAppearance = new AvatarAppearance(appearance, true);
182 acd.Appearance = npcAppearance; 202 acd.Appearance = npcAppearance;
183 203
184 lock (m_avatars) 204 /*
205 for (int i = 0;
206 i < acd.Appearance.Texture.FaceTextures.Length; i++)
185 { 207 {
186 scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, 208 m_log.DebugFormat(
187 acd); 209 "[NPC MODULE]: NPC avatar {0} has texture id {1} : {2}",
188 scene.AddNewAgent(npcAvatar, PresenceType.Npc); 210 acd.AgentID, i,
211 acd.Appearance.Texture.FaceTextures[i]);
212 }
213 */
189 214
190 ScenePresence sp; 215// ManualResetEvent ev = new ManualResetEvent(false);
191 if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp))
192 {
193 sp.CompleteMovement(npcAvatar, false);
194 m_avatars.Add(npcAvatar.AgentId, npcAvatar);
195 m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", npcAvatar.AgentId, sp.Name);
196 216
197 return npcAvatar.AgentId; 217// Util.FireAndForget(delegate(object x) {
198 } 218 lock (m_avatars)
199 else
200 { 219 {
201 m_log.WarnFormat( 220 scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, acd);
202 "[NPC MODULE]: Could not find scene presence for NPC {0} {1}", 221 scene.AddNewAgent(npcAvatar, PresenceType.Npc);
203 sp.Name, sp.UUID);
204 222
205 return UUID.Zero; 223 ScenePresence sp;
224 if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp))
225 {
226 npcAvatar.Born = born;
227 npcAvatar.ActiveGroupId = groupID;
228 sp.CompleteMovement(npcAvatar, false);
229 sp.Grouptitle = groupTitle;
230 m_avatars.Add(npcAvatar.AgentId, npcAvatar);
231// m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", npcAvatar.AgentId, sp.Name);
232 }
206 } 233 }
207 } 234// ev.Set();
235// });
236
237// ev.WaitOne();
238
239// m_log.DebugFormat("[NPC MODULE]: Created NPC with id {0}", npcAvatar.AgentId);
240
241 return npcAvatar.AgentId;
208 } 242 }
209 243
210 public bool MoveToTarget(UUID agentID, Scene scene, Vector3 pos, 244 public bool MoveToTarget(UUID agentID, Scene scene, Vector3 pos,
@@ -220,6 +254,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC
220 if (sp.IsSatOnObject || sp.SitGround) 254 if (sp.IsSatOnObject || sp.SitGround)
221 return false; 255 return false;
222 256
257// m_log.DebugFormat(
258// "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}",
259// sp.Name, pos, scene.RegionInfo.RegionName,
260// noFly, landAtTarget);
261
223 sp.MoveToTarget(pos, noFly, landAtTarget); 262 sp.MoveToTarget(pos, noFly, landAtTarget);
224 sp.SetAlwaysRun = running; 263 sp.SetAlwaysRun = running;
225 264
@@ -382,6 +421,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC
382 { 421 {
383 if (m_avatars.TryGetValue(agentID, out av)) 422 if (m_avatars.TryGetValue(agentID, out av))
384 { 423 {
424 /*
425 m_log.DebugFormat("[NPC MODULE]: Found {0} {1} to remove",
426 agentID, av.Name);
427 */
385 doRemove = true; 428 doRemove = true;
386 } 429 }
387 } 430 }
@@ -410,9 +453,15 @@ namespace OpenSim.Region.OptionalModules.World.NPC
410 { 453 {
411 NPCAvatar av; 454 NPCAvatar av;
412 if (m_avatars.TryGetValue(npcID, out av)) 455 if (m_avatars.TryGetValue(npcID, out av))
456 {
457 if (npcID == callerID)
458 return true;
413 return CheckPermissions(av, callerID); 459 return CheckPermissions(av, callerID);
460 }
414 else 461 else
462 {
415 return false; 463 return false;
464 }
416 } 465 }
417 } 466 }
418 467
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
112 // ScenePresence.SendInitialData() to reset our entire appearance. 112 // ScenePresence.SendInitialData() to reset our entire appearance.
113 m_scene.AssetService.Store(AssetHelpers.CreateNotecardAsset(originalFace8TextureId)); 113 m_scene.AssetService.Store(AssetHelpers.CreateNotecardAsset(originalFace8TextureId));
114 114
115 m_afMod.SetAppearance(sp, originalTe, null, null); 115 m_afMod.SetAppearance(sp, originalTe, null, new WearableCacheItem[0] );
116 116
117 UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance); 117 UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance);
118 118
@@ -209,10 +209,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
209 UserAccountHelpers.CreateUserWithInventory(m_scene, userId); 209 UserAccountHelpers.CreateUserWithInventory(m_scene, userId);
210 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); 210 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
211 211
212 InventoryItemBase att1Item 212 InventoryItemBase att1Item
213 = UserInventoryHelpers.CreateInventoryItem( 213 = UserInventoryHelpers.CreateInventoryItem(
214 m_scene, "att1", TestHelpers.ParseTail(0x2), TestHelpers.ParseTail(0x3), sp.UUID, InventoryType.Object); 214 m_scene, "att1", TestHelpers.ParseTail(0x2), TestHelpers.ParseTail(0x3), sp.UUID, InventoryType.Object);
215 InventoryItemBase att2Item 215 InventoryItemBase att2Item
216 = UserInventoryHelpers.CreateInventoryItem( 216 = UserInventoryHelpers.CreateInventoryItem(
217 m_scene, "att2", TestHelpers.ParseTail(0x12), TestHelpers.ParseTail(0x13), sp.UUID, InventoryType.Object); 217 m_scene, "att2", TestHelpers.ParseTail(0x12), TestHelpers.ParseTail(0x13), sp.UUID, InventoryType.Object);
218 218
@@ -483,4 +483,4 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
483 Assert.That(npc.ParentID, Is.EqualTo(0)); 483 Assert.That(npc.ParentID, Is.EqualTo(0));
484 } 484 }
485 } 485 }
486} \ No newline at end of file 486}
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
54 private Scene m_scene; 54 private Scene m_scene;
55 55
56 public string Name { get { return "Scene Commands Module"; } } 56 public string Name { get { return "Scene Commands Module"; } }
57 57
58 public Type ReplaceableInterface { get { return null; } } 58 public Type ReplaceableInterface { get { return null; } }
59 59
60 public void Initialise(IConfigSource source) 60 public void Initialise(IConfigSource source)
61 { 61 {
62// m_log.DebugFormat("[SCENE COMMANDS MODULE]: INITIALIZED MODULE"); 62// m_log.DebugFormat("[SCENE COMMANDS MODULE]: INITIALIZED MODULE");
63 } 63 }
64 64
65 public void PostInitialise() 65 public void PostInitialise()
66 { 66 {
67// m_log.DebugFormat("[SCENE COMMANDS MODULE]: POST INITIALIZED MODULE"); 67// m_log.DebugFormat("[SCENE COMMANDS MODULE]: POST INITIALIZED MODULE");
68 } 68 }
69 69
70 public void Close() 70 public void Close()
71 { 71 {
72// m_log.DebugFormat("[SCENE COMMANDS MODULE]: CLOSED MODULE"); 72// m_log.DebugFormat("[SCENE COMMANDS MODULE]: CLOSED MODULE");
73 } 73 }
74 74
75 public void AddRegion(Scene scene) 75 public void AddRegion(Scene scene)
76 { 76 {
77// m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); 77// m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
78 78
79 m_scene = scene; 79 m_scene = scene;
80 80
81 m_scene.RegisterModuleInterface<ISceneCommandsModule>(this); 81 m_scene.RegisterModuleInterface<ISceneCommandsModule>(this);
82 } 82 }
83 83
84 public void RemoveRegion(Scene scene) 84 public void RemoveRegion(Scene scene)
85 { 85 {
86// m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); 86// m_log.DebugFormat("[SCENE COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
87 } 87 }
88 88
89 public void RegionLoaded(Scene scene) 89 public void RegionLoaded(Scene scene)
90 { 90 {
91// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); 91// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
@@ -96,19 +96,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
96 "List current scene options.", 96 "List current scene options.",
97 "active - if false then main scene update and maintenance loops are suspended.\n" 97 "active - if false then main scene update and maintenance loops are suspended.\n"
98 + "animations - if true then extra animations debug information is logged.\n" 98 + "animations - if true then extra animations debug information is logged.\n"
99 + "appear-refresh - if true then appearance is resent to other avatars every 60 seconds.\n"
100 + "child-repri - how far an avatar must move in meters before we update the position of its child agents in neighbouring regions.\n"
101 + "client-pos-upd - the tolerance before clients are updated with new rotation information for an avatar.\n"
102 + "client-rot-upd - the tolerance before clients are updated with new rotation information for an avatar.\n"
103 + "client-vel-upd - the tolerance before clients are updated with new velocity information for an avatar.\n"
104 + "root-upd-per - if greater than 1, terse updates are only sent to root agents other than the originator on every n updates.\n"
105 + "child-upd-per - if greater than 1, terse updates are only sent to child agents on every n updates.\n"
106 + "collisions - if false then collisions with other objects are turned off.\n" 99 + "collisions - if false then collisions with other objects are turned off.\n"
107 + "pbackup - if false then periodic scene backup is turned off.\n" 100 + "pbackup - if false then periodic scene backup is turned off.\n"
108 + "physics - if false then all physics objects are non-physical.\n" 101 + "physics - if false then all physics objects are non-physical.\n"
109 + "scripting - if false then no scripting operations happen.\n" 102 + "scripting - if false then no scripting operations happen.\n"
110 + "teleport - if true then some extra teleport debug information is logged.\n" 103 + "teleport - if true then some extra teleport debug information is logged.\n"
111 + "update-on-timer - If true then the scene is updated via a timer. If false then a thread with sleep is used.\n"
112 + "updates - if true then any frame which exceeds double the maximum desired frame time is logged.", 104 + "updates - if true then any frame which exceeds double the maximum desired frame time is logged.",
113 HandleDebugSceneGetCommand); 105 HandleDebugSceneGetCommand);
114 106
@@ -118,19 +110,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
118 "Turn on scene debugging options.", 110 "Turn on scene debugging options.",
119 "active - if false then main scene update and maintenance loops are suspended.\n" 111 "active - if false then main scene update and maintenance loops are suspended.\n"
120 + "animations - if true then extra animations debug information is logged.\n" 112 + "animations - if true then extra animations debug information is logged.\n"
121 + "appear-refresh - if true then appearance is resent to other avatars every 60 seconds.\n"
122 + "child-repri - how far an avatar must move in meters before we update the position of its child agents in neighbouring regions.\n"
123 + "client-pos-upd - the tolerance before clients are updated with new rotation information for an avatar.\n"
124 + "client-rot-upd - the tolerance before clients are updated with new rotation information for an avatar.\n"
125 + "client-vel-upd - the tolerance before clients are updated with new velocity information for an avatar.\n"
126 + "root-upd-per - if greater than 1, terse updates are only sent to root agents other than the originator on every n updates.\n"
127 + "child-upd-per - if greater than 1, terse updates are only sent to child agents on every n updates.\n"
128 + "collisions - if false then collisions with other objects are turned off.\n" 113 + "collisions - if false then collisions with other objects are turned off.\n"
129 + "pbackup - if false then periodic scene backup is turned off.\n" 114 + "pbackup - if false then periodic scene backup is turned off.\n"
130 + "physics - if false then all physics objects are non-physical.\n" 115 + "physics - if false then all physics objects are non-physical.\n"
131 + "scripting - if false then no scripting operations happen.\n" 116 + "scripting - if false then no scripting operations happen.\n"
132 + "teleport - if true then some extra teleport debug information is logged.\n" 117 + "teleport - if true then some extra teleport debug information is logged.\n"
133 + "update-on-timer - If true then the scene is updated via a timer. If false then a thread with sleep is used.\n"
134 + "updates - if true then any frame which exceeds double the maximum desired frame time is logged.", 118 + "updates - if true then any frame which exceeds double the maximum desired frame time is logged.",
135 HandleDebugSceneSetCommand); 119 HandleDebugSceneSetCommand);
136 } 120 }
@@ -155,18 +139,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
155 ConsoleDisplayList cdl = new ConsoleDisplayList(); 139 ConsoleDisplayList cdl = new ConsoleDisplayList();
156 cdl.AddRow("active", m_scene.Active); 140 cdl.AddRow("active", m_scene.Active);
157 cdl.AddRow("animations", m_scene.DebugAnimations); 141 cdl.AddRow("animations", m_scene.DebugAnimations);
158 cdl.AddRow("appear-refresh", m_scene.SendPeriodicAppearanceUpdates);
159 cdl.AddRow("child-repri", m_scene.ChildReprioritizationDistance);
160 cdl.AddRow("client-pos-upd", m_scene.RootPositionUpdateTolerance);
161 cdl.AddRow("client-rot-upd", m_scene.RootRotationUpdateTolerance);
162 cdl.AddRow("client-vel-upd", m_scene.RootVelocityUpdateTolerance);
163 cdl.AddRow("root-upd-per", m_scene.RootTerseUpdatePeriod);
164 cdl.AddRow("child-upd-per", m_scene.ChildTerseUpdatePeriod);
165 cdl.AddRow("pbackup", m_scene.PeriodicBackup); 142 cdl.AddRow("pbackup", m_scene.PeriodicBackup);
166 cdl.AddRow("physics", m_scene.PhysicsEnabled); 143 cdl.AddRow("physics", m_scene.PhysicsEnabled);
167 cdl.AddRow("scripting", m_scene.ScriptsEnabled); 144 cdl.AddRow("scripting", m_scene.ScriptsEnabled);
168 cdl.AddRow("teleport", m_scene.DebugTeleporting); 145 cdl.AddRow("teleport", m_scene.DebugTeleporting);
169 cdl.AddRow("update-on-timer", m_scene.UpdateOnTimer);
170 cdl.AddRow("updates", m_scene.DebugUpdates); 146 cdl.AddRow("updates", m_scene.DebugUpdates);
171 147
172 MainConsole.Instance.OutputFormat("Scene {0} options:", m_scene.Name); 148 MainConsole.Instance.OutputFormat("Scene {0} options:", m_scene.Name);
@@ -210,69 +186,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
210 m_scene.DebugAnimations = active; 186 m_scene.DebugAnimations = active;
211 } 187 }
212 188
213 if (options.ContainsKey("appear-refresh"))
214 {
215 bool newValue;
216
217 // FIXME: This can only come from the console at the moment but might not always be true.
218 if (ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, options["appear-refresh"], out newValue))
219 m_scene.SendPeriodicAppearanceUpdates = newValue;
220 }
221
222 if (options.ContainsKey("child-repri"))
223 {
224 double newValue;
225
226 // FIXME: This can only come from the console at the moment but might not always be true.
227 if (ConsoleUtil.TryParseConsoleDouble(MainConsole.Instance, options["child-repri"], out newValue))
228 m_scene.ChildReprioritizationDistance = newValue;
229 }
230
231 if (options.ContainsKey("client-pos-upd"))
232 {
233 float newValue;
234
235 // FIXME: This can only come from the console at the moment but might not always be true.
236 if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-pos-upd"], out newValue))
237 m_scene.RootPositionUpdateTolerance = newValue;
238 }
239
240 if (options.ContainsKey("client-rot-upd"))
241 {
242 float newValue;
243
244 // FIXME: This can only come from the console at the moment but might not always be true.
245 if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-rot-upd"], out newValue))
246 m_scene.RootRotationUpdateTolerance = newValue;
247 }
248
249 if (options.ContainsKey("client-vel-upd"))
250 {
251 float newValue;
252
253 // FIXME: This can only come from the console at the moment but might not always be true.
254 if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-vel-upd"], out newValue))
255 m_scene.RootVelocityUpdateTolerance = newValue;
256 }
257
258 if (options.ContainsKey("root-upd-per"))
259 {
260 int newValue;
261
262 // FIXME: This can only come from the console at the moment but might not always be true.
263 if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, options["root-upd-per"], out newValue))
264 m_scene.RootTerseUpdatePeriod = newValue;
265 }
266
267 if (options.ContainsKey("child-upd-per"))
268 {
269 int newValue;
270
271 // FIXME: This can only come from the console at the moment but might not always be true.
272 if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, options["child-upd-per"], out newValue))
273 m_scene.ChildTerseUpdatePeriod = newValue;
274 }
275
276 if (options.ContainsKey("pbackup")) 189 if (options.ContainsKey("pbackup"))
277 { 190 {
278 bool active; 191 bool active;
@@ -308,21 +221,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
308 m_scene.DebugTeleporting = enableTeleportDebugging; 221 m_scene.DebugTeleporting = enableTeleportDebugging;
309 } 222 }
310 223
311 if (options.ContainsKey("update-on-timer"))
312 {
313 bool enableUpdateOnTimer;
314 if (bool.TryParse(options["update-on-timer"], out enableUpdateOnTimer))
315 {
316 m_scene.UpdateOnTimer = enableUpdateOnTimer;
317 m_scene.Active = false;
318
319 while (m_scene.IsRunning)
320 Thread.Sleep(20);
321
322 m_scene.Active = true;
323 }
324 }
325
326 if (options.ContainsKey("updates")) 224 if (options.ContainsKey("updates"))
327 { 225 {
328 bool enableUpdateDebugging; 226 bool enableUpdateDebugging;
@@ -334,4 +232,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
334 } 232 }
335 } 233 }
336 } 234 }
337} \ No newline at end of file 235}
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 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.IO;
30using System.Reflection; 31using System.Reflection;
31using System.Timers; 32using System.Timers;
33using System.Threading;
34using System.Xml;
35using System.Xml.Serialization;
36
32using OpenMetaverse; 37using OpenMetaverse;
33using log4net; 38using log4net;
34using Mono.Addins; 39using Mono.Addins;
@@ -38,17 +43,15 @@ using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
38using OpenSim.Region.Framework.Interfaces; 43using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 44using OpenSim.Region.Framework.Scenes;
40 45
41using System.Xml; 46using Timer= System.Timers.Timer;
42using System.Xml.Serialization;
43using System.IO;
44 47
45namespace OpenSim.Region.OptionalModules.World.TreePopulator 48namespace OpenSim.Region.OptionalModules.World.TreePopulator
46{ 49{
47 /// <summary> 50 /// <summary>
48 /// Version 2.02 - Still hacky 51 /// Version 2.02 - Still hacky
49 /// </summary> 52 /// </summary>
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "TreePopulatorModule")] 53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "TreePopulatorModule")]
51 public class TreePopulatorModule : INonSharedRegionModule, ICommandableModule, IVegetationModule 54 public class TreePopulatorModule : INonSharedRegionModule, ICommandableModule
52 { 55 {
53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54 private readonly Commander m_commander = new Commander("tree"); 57 private readonly Commander m_commander = new Commander("tree");
@@ -60,7 +63,7 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
60 public string m_name; 63 public string m_name;
61 public Boolean m_frozen; 64 public Boolean m_frozen;
62 public Tree m_tree_type; 65 public Tree m_tree_type;
63 public int m_tree_quantity; 66 public int m_tree_quantity;
64 public float m_treeline_low; 67 public float m_treeline_low;
65 public float m_treeline_high; 68 public float m_treeline_high;
66 public Vector3 m_seed_point; 69 public Vector3 m_seed_point;
@@ -78,24 +81,24 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
78 { 81 {
79 } 82 }
80 83
81 public Copse(string fileName, Boolean planted) 84 public Copse(string fileName, Boolean planted)
82 { 85 {
83 Copse cp = (Copse)DeserializeObject(fileName); 86 Copse cp = (Copse)DeserializeObject(fileName);
84 87
85 this.m_name = cp.m_name; 88 m_name = cp.m_name;
86 this.m_frozen = cp.m_frozen; 89 m_frozen = cp.m_frozen;
87 this.m_tree_quantity = cp.m_tree_quantity; 90 m_tree_quantity = cp.m_tree_quantity;
88 this.m_treeline_high = cp.m_treeline_high; 91 m_treeline_high = cp.m_treeline_high;
89 this.m_treeline_low = cp.m_treeline_low; 92 m_treeline_low = cp.m_treeline_low;
90 this.m_range = cp.m_range; 93 m_range = cp.m_range;
91 this.m_tree_type = cp.m_tree_type; 94 m_tree_type = cp.m_tree_type;
92 this.m_seed_point = cp.m_seed_point; 95 m_seed_point = cp.m_seed_point;
93 this.m_initial_scale = cp.m_initial_scale; 96 m_initial_scale = cp.m_initial_scale;
94 this.m_maximum_scale = cp.m_maximum_scale; 97 m_maximum_scale = cp.m_maximum_scale;
95 this.m_initial_scale = cp.m_initial_scale; 98 m_initial_scale = cp.m_initial_scale;
96 this.m_rate = cp.m_rate; 99 m_rate = cp.m_rate;
97 this.m_planted = planted; 100 m_planted = planted;
98 this.m_trees = new List<UUID>(); 101 m_trees = new List<UUID>();
99 } 102 }
100 103
101 public Copse(string copsedef) 104 public Copse(string copsedef)
@@ -103,61 +106,63 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
103 char[] delimiterChars = {':', ';'}; 106 char[] delimiterChars = {':', ';'};
104 string[] field = copsedef.Split(delimiterChars); 107 string[] field = copsedef.Split(delimiterChars);
105 108
106 this.m_name = field[1].Trim(); 109 m_name = field[1].Trim();
107 this.m_frozen = (copsedef[0] == 'F'); 110 m_frozen = (copsedef[0] == 'F');
108 this.m_tree_quantity = int.Parse(field[2]); 111 m_tree_quantity = int.Parse(field[2]);
109 this.m_treeline_high = float.Parse(field[3], Culture.NumberFormatInfo); 112 m_treeline_high = float.Parse(field[3], Culture.NumberFormatInfo);
110 this.m_treeline_low = float.Parse(field[4], Culture.NumberFormatInfo); 113 m_treeline_low = float.Parse(field[4], Culture.NumberFormatInfo);
111 this.m_range = double.Parse(field[5], Culture.NumberFormatInfo); 114 m_range = double.Parse(field[5], Culture.NumberFormatInfo);
112 this.m_tree_type = (Tree) Enum.Parse(typeof(Tree),field[6]); 115 m_tree_type = (Tree) Enum.Parse(typeof(Tree),field[6]);
113 this.m_seed_point = Vector3.Parse(field[7]); 116 m_seed_point = Vector3.Parse(field[7]);
114 this.m_initial_scale = Vector3.Parse(field[8]); 117 m_initial_scale = Vector3.Parse(field[8]);
115 this.m_maximum_scale = Vector3.Parse(field[9]); 118 m_maximum_scale = Vector3.Parse(field[9]);
116 this.m_rate = Vector3.Parse(field[10]); 119 m_rate = Vector3.Parse(field[10]);
117 this.m_planted = true; 120 m_planted = true;
118 this.m_trees = new List<UUID>(); 121 m_trees = new List<UUID>();
119 } 122 }
120 123
121 public Copse(string name, int quantity, float high, float low, double range, Vector3 point, Tree type, Vector3 scale, Vector3 max_scale, Vector3 rate, List<UUID> trees) 124 public Copse(string name, int quantity, float high, float low, double range, Vector3 point, Tree type, Vector3 scale, Vector3 max_scale, Vector3 rate, List<UUID> trees)
122 { 125 {
123 this.m_name = name; 126 m_name = name;
124 this.m_frozen = false; 127 m_frozen = false;
125 this.m_tree_quantity = quantity; 128 m_tree_quantity = quantity;
126 this.m_treeline_high = high; 129 m_treeline_high = high;
127 this.m_treeline_low = low; 130 m_treeline_low = low;
128 this.m_range = range; 131 m_range = range;
129 this.m_tree_type = type; 132 m_tree_type = type;
130 this.m_seed_point = point; 133 m_seed_point = point;
131 this.m_initial_scale = scale; 134 m_initial_scale = scale;
132 this.m_maximum_scale = max_scale; 135 m_maximum_scale = max_scale;
133 this.m_rate = rate; 136 m_rate = rate;
134 this.m_planted = false; 137 m_planted = false;
135 this.m_trees = trees; 138 m_trees = trees;
136 } 139 }
137 140
138 public override string ToString() 141 public override string ToString()
139 { 142 {
140 string frozen = (this.m_frozen ? "F" : "A"); 143 string frozen = (m_frozen ? "F" : "A");
141 144
142 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};", 145 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};",
143 frozen, 146 frozen,
144 this.m_name, 147 m_name,
145 this.m_tree_quantity, 148 m_tree_quantity,
146 this.m_treeline_high, 149 m_treeline_high,
147 this.m_treeline_low, 150 m_treeline_low,
148 this.m_range, 151 m_range,
149 this.m_tree_type, 152 m_tree_type,
150 this.m_seed_point.ToString(), 153 m_seed_point.ToString(),
151 this.m_initial_scale.ToString(), 154 m_initial_scale.ToString(),
152 this.m_maximum_scale.ToString(), 155 m_maximum_scale.ToString(),
153 this.m_rate.ToString()); 156 m_rate.ToString());
154 } 157 }
155 } 158 }
156 159
157 private List<Copse> m_copse; 160 private List<Copse> m_copses = new List<Copse>();
158 161 private object mylock;
159 private double m_update_ms = 1000.0; // msec between updates 162 private double m_update_ms = 1000.0; // msec between updates
160 private bool m_active_trees = false; 163 private bool m_active_trees = false;
164 private bool m_enabled = true; // original default
165 private bool m_allowGrow = true; // original default
161 166
162 Timer CalculateTrees; 167 Timer CalculateTrees;
163 168
@@ -174,51 +179,51 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
174 179
175 public void Initialise(IConfigSource config) 180 public void Initialise(IConfigSource config)
176 { 181 {
177 182 IConfig moduleConfig = config.Configs["Trees"];
178 // ini file settings 183 if (moduleConfig != null)
179 try
180 { 184 {
181 m_active_trees = config.Configs["Trees"].GetBoolean("active_trees", m_active_trees); 185 m_enabled = moduleConfig.GetBoolean("enabled", m_enabled);
182 } 186 m_active_trees = moduleConfig.GetBoolean("active_trees", m_active_trees);
183 catch (Exception) 187 m_allowGrow = moduleConfig.GetBoolean("allowGrow", m_allowGrow);
184 { 188 m_update_ms = moduleConfig.GetDouble("update_rate", m_update_ms);
185 m_log.Debug("[TREES]: ini failure for active_trees - using default");
186 } 189 }
187 190
188 try 191 if(!m_enabled)
189 { 192 return;
190 m_update_ms = config.Configs["Trees"].GetDouble("update_rate", m_update_ms); 193
191 } 194 m_copses = new List<Copse>();
192 catch (Exception) 195 mylock = new object();
193 {
194 m_log.Debug("[TREES]: ini failure for update_rate - using default");
195 }
196 196
197 InstallCommands(); 197 InstallCommands();
198 198
199 m_log.Debug("[TREES]: Initialised tree module"); 199 m_log.Debug("[TREES]: Initialised tree populator module");
200 } 200 }
201 201
202 public void AddRegion(Scene scene) 202 public void AddRegion(Scene scene)
203 { 203 {
204 if(!m_enabled)
205 return;
204 m_scene = scene; 206 m_scene = scene;
205 m_scene.RegisterModuleCommander(m_commander); 207 m_scene.RegisterModuleCommander(m_commander);
206 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; 208 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
207 209 m_scene.EventManager.OnPrimsLoaded += EventManager_OnPrimsLoaded;
208 } 210 }
209 211
210 public void RemoveRegion(Scene scene) 212 public void RemoveRegion(Scene scene)
211 { 213 {
212 } 214 if(!m_enabled)
215 return;
216 if(m_active_trees && CalculateTrees != null)
217 {
218 CalculateTrees.Dispose();
219 CalculateTrees = null;
220 }
221 m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole;
222 m_scene.EventManager.OnPrimsLoaded -= EventManager_OnPrimsLoaded;
223 }
213 224
214 public void RegionLoaded(Scene scene) 225 public void RegionLoaded(Scene scene)
215 { 226 {
216 ReloadCopse();
217 if (m_copse.Count > 0)
218 m_log.Info("[TREES]: Copse load complete");
219
220 if (m_active_trees)
221 activeizeTreeze(true);
222 } 227 }
223 228
224 public void Close() 229 public void Close()
@@ -240,6 +245,16 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
240 245
241 //-------------------------------------------------------------- 246 //--------------------------------------------------------------
242 247
248 private void EventManager_OnPrimsLoaded(Scene s)
249 {
250 ReloadCopse();
251 if (m_copses.Count > 0)
252 m_log.Info("[TREES]: Copses loaded" );
253
254 if (m_active_trees)
255 activeizeTreeze(true);
256 }
257
243 #region ICommandableModule Members 258 #region ICommandableModule Members
244 259
245 private void HandleTreeActive(Object[] args) 260 private void HandleTreeActive(Object[] args)
@@ -267,25 +282,57 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
267 string copsename = ((string)args[0]).Trim(); 282 string copsename = ((string)args[0]).Trim();
268 Boolean freezeState = (Boolean) args[1]; 283 Boolean freezeState = (Boolean) args[1];
269 284
270 foreach (Copse cp in m_copse) 285 lock(mylock)
271 { 286 {
272 if (cp.m_name == copsename && (!cp.m_frozen && freezeState || cp.m_frozen && !freezeState)) 287 foreach (Copse cp in m_copses)
273 { 288 {
274 cp.m_frozen = freezeState; 289 if (cp.m_name != copsename)
275 foreach (UUID tree in cp.m_trees) 290 continue;
291
292 if(!cp.m_frozen && freezeState || cp.m_frozen && !freezeState)
276 { 293 {
277 SceneObjectPart sop = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart; 294 cp.m_frozen = freezeState;
278 sop.Name = (freezeState ? sop.Name.Replace("ATPM", "FTPM") : sop.Name.Replace("FTPM", "ATPM")); 295 List<UUID> losttrees = new List<UUID>();
279 sop.ParentGroup.HasGroupChanged = true; 296 foreach (UUID tree in cp.m_trees)
280 } 297 {
298 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(tree);
299 if(sog != null && !sog.IsDeleted)
300 {
301 SceneObjectPart sop = sog.RootPart;
302 string name = sop.Name;
303 if(freezeState)
304 {
305 if(name.StartsWith("FTPM"))
306 continue;
307 if(!name.StartsWith("ATPM"))
308 continue;
309 sop.Name = sop.Name.Replace("ATPM", "FTPM");
310 }
311 else
312 {
313 if(name.StartsWith("ATPM"))
314 continue;
315 if(!name.StartsWith("FTPM"))
316 continue;
317 sop.Name = sop.Name.Replace("FTPM", "ATPM");
318 }
319 sop.ParentGroup.HasGroupChanged = true;
320 sog.ScheduleGroupForFullUpdate();
321 }
322 else
323 losttrees.Add(tree);
324 }
325 foreach (UUID tree in losttrees)
326 cp.m_trees.Remove(tree);
281 327
282 m_log.InfoFormat("[TREES]: Activity for copse {0} is frozen {1}", copsename, freezeState); 328 m_log.InfoFormat("[TREES]: Activity for copse {0} is frozen {1}", copsename, freezeState);
283 return; 329 return;
284 } 330 }
285 else if (cp.m_name == copsename && (cp.m_frozen && freezeState || !cp.m_frozen && !freezeState)) 331 else
286 { 332 {
287 m_log.InfoFormat("[TREES]: Copse {0} is already in the requested freeze state", copsename); 333 m_log.InfoFormat("[TREES]: Copse {0} is already in the requested freeze state", copsename);
288 return; 334 return;
335 }
289 } 336 }
290 } 337 }
291 m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename); 338 m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename);
@@ -297,17 +344,21 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
297 344
298 m_log.InfoFormat("[TREES]: Loading copse definition...."); 345 m_log.InfoFormat("[TREES]: Loading copse definition....");
299 346
300 copse = new Copse(((string)args[0]), false); 347 lock(mylock)
301 foreach (Copse cp in m_copse)
302 { 348 {
303 if (cp.m_name == copse.m_name) 349 copse = new Copse(((string)args[0]), false);
304 { 350 {
305 m_log.InfoFormat("[TREES]: Copse: {0} is already defined - command failed", copse.m_name); 351 foreach (Copse cp in m_copses)
306 return; 352 {
353 if (cp.m_name == copse.m_name)
354 {
355 m_log.InfoFormat("[TREES]: Copse: {0} is already defined - command failed", copse.m_name);
356 return;
357 }
358 }
307 } 359 }
360 m_copses.Add(copse);
308 } 361 }
309
310 m_copse.Add(copse);
311 m_log.InfoFormat("[TREES]: Loaded copse: {0}", copse.ToString()); 362 m_log.InfoFormat("[TREES]: Loaded copse: {0}", copse.ToString());
312 } 363 }
313 364
@@ -318,20 +369,24 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
318 m_log.InfoFormat("[TREES]: New tree planting for copse {0}", copsename); 369 m_log.InfoFormat("[TREES]: New tree planting for copse {0}", copsename);
319 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; 370 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
320 371
321 foreach (Copse copse in m_copse) 372 lock(mylock)
322 { 373 {
323 if (copse.m_name == copsename) 374 foreach (Copse copse in m_copses)
324 { 375 {
325 if (!copse.m_planted) 376 if (copse.m_name == copsename)
326 {
327 // The first tree for a copse is created here
328 CreateTree(uuid, copse, copse.m_seed_point);
329 copse.m_planted = true;
330 return;
331 }
332 else
333 { 377 {
334 m_log.InfoFormat("[TREES]: Copse {0} has already been planted", copsename); 378 if (!copse.m_planted)
379 {
380 // The first tree for a copse is created here
381 CreateTree(uuid, copse, copse.m_seed_point, true);
382 copse.m_planted = true;
383 return;
384 }
385 else
386 {
387 m_log.InfoFormat("[TREES]: Copse {0} has already been planted", copsename);
388 return;
389 }
335 } 390 }
336 } 391 }
337 } 392 }
@@ -376,45 +431,49 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
376 string copsename = ((string)args[0]).Trim(); 431 string copsename = ((string)args[0]).Trim();
377 Copse copseIdentity = null; 432 Copse copseIdentity = null;
378 433
379 foreach (Copse cp in m_copse) 434 lock(mylock)
380 { 435 {
381 if (cp.m_name == copsename) 436 foreach (Copse cp in m_copses)
382 { 437 {
383 copseIdentity = cp; 438 if (cp.m_name == copsename)
439 {
440 copseIdentity = cp;
441 }
384 } 442 }
385 }
386 443
387 if (copseIdentity != null) 444 if (copseIdentity != null)
388 {
389 foreach (UUID tree in copseIdentity.m_trees)
390 { 445 {
391 if (m_scene.Entities.ContainsKey(tree)) 446 foreach (UUID tree in copseIdentity.m_trees)
392 {
393 SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
394 // Delete tree and alert clients (not silent)
395 m_scene.DeleteSceneObject(selectedTree.ParentGroup, false);
396 }
397 else
398 { 447 {
399 m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); 448 if (m_scene.Entities.ContainsKey(tree))
449 {
450 SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
451 // Delete tree and alert clients (not silent)
452 m_scene.DeleteSceneObject(selectedTree.ParentGroup, false);
453 }
454 else
455 {
456 m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree);
457 }
400 } 458 }
459 copseIdentity.m_trees = null;
460 m_copses.Remove(copseIdentity);
461 m_log.InfoFormat("[TREES]: Copse {0} has been removed", copsename);
462 }
463 else
464 {
465 m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename);
401 } 466 }
402 copseIdentity.m_trees = new List<UUID>();
403 m_copse.Remove(copseIdentity);
404 m_log.InfoFormat("[TREES]: Copse {0} has been removed", copsename);
405 }
406 else
407 {
408 m_log.InfoFormat("[TREES]: Copse {0} was not found - command failed", copsename);
409 } 467 }
410 } 468 }
411 469
412 private void HandleTreeStatistics(Object[] args) 470 private void HandleTreeStatistics(Object[] args)
413 { 471 {
414 m_log.InfoFormat("[TREES]: Activity State: {0}; Update Rate: {1}", m_active_trees, m_update_ms); 472 m_log.InfoFormat("[TREES]: region {0}:", m_scene.Name);
415 foreach (Copse cp in m_copse) 473 m_log.InfoFormat("[TREES]: Activity State: {0}; Update Rate: {1}", m_active_trees, m_update_ms);
474 foreach (Copse cp in m_copses)
416 { 475 {
417 m_log.InfoFormat("[TREES]: Copse {0}; {1} trees; frozen {2}", cp.m_name, cp.m_trees.Count, cp.m_frozen); 476 m_log.InfoFormat("[TREES]: Copse {0}; {1} trees; frozen {2}", cp.m_name, cp.m_trees.Count, cp.m_frozen);
418 } 477 }
419 } 478 }
420 479
@@ -442,7 +501,7 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
442 treeRateCommand.AddArgument("updateRate", "The required update rate (minimum 1000.0)", "Double"); 501 treeRateCommand.AddArgument("updateRate", "The required update rate (minimum 1000.0)", "Double");
443 502
444 Command treeReloadCommand = 503 Command treeReloadCommand =
445 new Command("reload", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeReload, "Reload copse definitions from the in-scene trees"); 504 new Command("reload", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeReload, "Reload copses from the in-scene trees");
446 505
447 Command treeRemoveCommand = 506 Command treeRemoveCommand =
448 new Command("remove", CommandIntentions.COMMAND_HAZARDOUS, HandleTreeRemove, "Remove a copse definition and all its in-scene trees"); 507 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
499 treeShape.Scale = scale; 558 treeShape.Scale = scale;
500 treeShape.State = (byte)treeType; 559 treeShape.State = (byte)treeType;
501 560
502 return m_scene.AddNewPrim(uuid, groupID, position, rotation, treeShape); 561 SceneObjectGroup sog = new SceneObjectGroup(uuid, position, rotation, treeShape);
503 } 562 SceneObjectPart rootPart = sog.RootPart;
504
505 #endregion
506
507 #region IEntityCreator Members
508
509 protected static readonly PCode[] creationCapabilities = new PCode[] { PCode.NewTree, PCode.Tree };
510 public PCode[] CreationCapabilities { get { return creationCapabilities; } }
511
512 public SceneObjectGroup CreateEntity(
513 UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
514 {
515 if (Array.IndexOf(creationCapabilities, (PCode)shape.PCode) < 0)
516 {
517 m_log.DebugFormat("[VEGETATION]: PCode {0} not handled by {1}", shape.PCode, Name);
518 return null;
519 }
520
521 SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape);
522 SceneObjectPart rootPart = sceneObject.GetPart(sceneObject.UUID);
523 563
524 rootPart.AddFlag(PrimFlags.Phantom); 564 rootPart.AddFlag(PrimFlags.Phantom);
525 565
526 m_scene.AddNewSceneObject(sceneObject, true); 566 sog.SetGroup(groupID, null);
527 sceneObject.SetGroup(groupID, null); 567 m_scene.AddNewSceneObject(sog, true, false);
528 568 sog.IsSelected = false;
529 return sceneObject; 569 rootPart.IsSelected = false;
570 sog.InvalidateEffectivePerms();
571 return sog;
530 } 572 }
531 573
532 #endregion 574 #endregion
@@ -569,26 +611,27 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
569 611
570 private void ReloadCopse() 612 private void ReloadCopse()
571 { 613 {
572 m_copse = new List<Copse>(); 614 m_copses = new List<Copse>();
573 615
574 EntityBase[] objs = m_scene.GetEntities(); 616 List<SceneObjectGroup> grps = m_scene.GetSceneObjectGroups();
575 foreach (EntityBase obj in objs) 617 foreach (SceneObjectGroup grp in grps)
576 { 618 {
577 if (obj is SceneObjectGroup) 619 if(grp.RootPart.Shape.PCode != (byte)PCode.NewTree && grp.RootPart.Shape.PCode != (byte)PCode.Tree)
578 { 620 continue;
579 SceneObjectGroup grp = (SceneObjectGroup)obj;
580 621
581 if (grp.Name.Length > 5 && (grp.Name.Substring(0, 5) == "ATPM:" || grp.Name.Substring(0, 5) == "FTPM:")) 622 if (grp.Name.Length > 5 && (grp.Name.Substring(0, 5) == "ATPM:" || grp.Name.Substring(0, 5) == "FTPM:"))
623 {
624 // Create a new copse definition or add uuid to an existing definition
625 try
582 { 626 {
583 // Create a new copse definition or add uuid to an existing definition 627 Boolean copsefound = false;
584 try 628 Copse grpcopse = new Copse(grp.Name);
585 {
586 Boolean copsefound = false;
587 Copse copse = new Copse(grp.Name);
588 629
589 foreach (Copse cp in m_copse) 630 lock(mylock)
631 {
632 foreach (Copse cp in m_copses)
590 { 633 {
591 if (cp.m_name == copse.m_name) 634 if (cp.m_name == grpcopse.m_name)
592 { 635 {
593 copsefound = true; 636 copsefound = true;
594 cp.m_trees.Add(grp.UUID); 637 cp.m_trees.Add(grp.UUID);
@@ -598,15 +641,15 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
598 641
599 if (!copsefound) 642 if (!copsefound)
600 { 643 {
601 m_log.InfoFormat("[TREES]: Found copse {0}", grp.Name); 644 m_log.InfoFormat("[TREES]: adding copse {0}", grpcopse.m_name);
602 m_copse.Add(copse); 645 grpcopse.m_trees.Add(grp.UUID);
603 copse.m_trees.Add(grp.UUID); 646 m_copses.Add(grpcopse);
604 } 647 }
605 } 648 }
606 catch 649 }
607 { 650 catch
608 m_log.InfoFormat("[TREES]: Ill formed copse definition {0} - ignoring", grp.Name); 651 {
609 } 652 m_log.InfoFormat("[TREES]: Ill formed copse definition {0} - ignoring", grp.Name);
610 } 653 }
611 } 654 }
612 } 655 }
@@ -617,166 +660,265 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
617 { 660 {
618 if (activeYN) 661 if (activeYN)
619 { 662 {
620 CalculateTrees = new Timer(m_update_ms); 663 if(CalculateTrees == null)
664 CalculateTrees = new Timer(m_update_ms);
621 CalculateTrees.Elapsed += CalculateTrees_Elapsed; 665 CalculateTrees.Elapsed += CalculateTrees_Elapsed;
666 CalculateTrees.AutoReset = false;
622 CalculateTrees.Start(); 667 CalculateTrees.Start();
623 } 668 }
624 else 669 else
625 { 670 {
626 CalculateTrees.Stop(); 671 CalculateTrees.Stop();
627 } 672 }
628 } 673 }
629 674
630 private void growTrees() 675 private void growTrees()
631 { 676 {
632 foreach (Copse copse in m_copse) 677 if(!m_allowGrow)
678 return;
679
680 foreach (Copse copse in m_copses)
633 { 681 {
634 if (!copse.m_frozen) 682 if (copse.m_frozen)
683 continue;
684
685 if(copse.m_trees.Count == 0)
686 continue;
687
688 float maxscale = copse.m_maximum_scale.Z;
689 float ratescale = 1.0f;
690 List<UUID> losttrees = new List<UUID>();
691 foreach (UUID tree in copse.m_trees)
635 { 692 {
636 foreach (UUID tree in copse.m_trees) 693 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(tree);
637 {
638 if (m_scene.Entities.ContainsKey(tree))
639 {
640 SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
641 694
642 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) 695 if (sog != null && !sog.IsDeleted)
643 { 696 {
644 s_tree.Scale += copse.m_rate; 697 SceneObjectPart s_tree = sog.RootPart;
645 s_tree.ParentGroup.HasGroupChanged = true; 698 if (s_tree.Scale.Z < maxscale)
646 s_tree.ScheduleFullUpdate();
647 }
648 }
649 else
650 { 699 {
651 m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); 700 ratescale = (float)Util.RandomClass.NextDouble();
701 if(ratescale < 0.2f)
702 ratescale = 0.2f;
703 s_tree.Scale += copse.m_rate * ratescale;
704 sog.HasGroupChanged = true;
705 s_tree.ScheduleFullUpdate();
652 } 706 }
653 } 707 }
708 else
709 losttrees.Add(tree);
654 } 710 }
711
712 foreach (UUID tree in losttrees)
713 copse.m_trees.Remove(tree);
655 } 714 }
656 } 715 }
657 716
658 private void seedTrees() 717 private void seedTrees()
659 { 718 {
660 foreach (Copse copse in m_copse) 719 foreach (Copse copse in m_copses)
661 { 720 {
662 if (!copse.m_frozen) 721 if (copse.m_frozen)
722 continue;
723
724 if(copse.m_trees.Count == 0)
725 return;
726
727 bool low = copse.m_trees.Count < (int)(copse.m_tree_quantity * 0.8f);
728
729 if (!low && Util.RandomClass.NextDouble() < 0.75)
730 return;
731
732 int maxbirths = (int)(copse.m_tree_quantity) - copse.m_trees.Count;
733 if(maxbirths <= 1)
734 return;
735
736 if(maxbirths > 20)
737 maxbirths = 20;
738
739 float minscale = 0;
740 if(!low && m_allowGrow)
741 minscale = copse.m_maximum_scale.Z * 0.75f;;
742
743 int i = 0;
744 UUID[] current = copse.m_trees.ToArray();
745 while(--maxbirths > 0)
663 { 746 {
664 foreach (UUID tree in copse.m_trees) 747 if(current.Length > 1)
748 i = Util.RandomClass.Next(current.Length -1);
749
750 UUID tree = current[i];
751 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(tree);
752
753 if (sog != null && !sog.IsDeleted)
665 { 754 {
666 if (m_scene.Entities.ContainsKey(tree)) 755 SceneObjectPart s_tree = sog.RootPart;
667 {
668 SceneObjectPart s_tree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
669 756
670 if (copse.m_trees.Count < copse.m_tree_quantity) 757 // Tree has grown enough to seed if it has grown by at least 25% of seeded to full grown height
671 { 758 if (s_tree.Scale.Z > minscale)
672 // Tree has grown enough to seed if it has grown by at least 25% of seeded to full grown height 759 SpawnChild(copse, s_tree, true);
673 if (s_tree.Scale.Z > copse.m_initial_scale.Z + (copse.m_maximum_scale.Z - copse.m_initial_scale.Z) / 4.0)
674 {
675 if (Util.RandomClass.NextDouble() > 0.75)
676 {
677 SpawnChild(copse, s_tree);
678 }
679 }
680 }
681 }
682 else
683 {
684 m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree);
685 }
686 } 760 }
687 } 761 else if(copse.m_trees.Contains(tree))
762 copse.m_trees.Remove(tree);
763 }
688 } 764 }
689 } 765 }
690 766
691 private void killTrees() 767 private void killTrees()
692 { 768 {
693 foreach (Copse copse in m_copse) 769 foreach (Copse copse in m_copses)
694 { 770 {
695 if (!copse.m_frozen && copse.m_trees.Count >= copse.m_tree_quantity) 771 if (copse.m_frozen)
696 { 772 continue;
697 foreach (UUID tree in copse.m_trees)
698 {
699 double killLikelyhood = 0.0;
700 773
701 if (m_scene.Entities.ContainsKey(tree)) 774 if (Util.RandomClass.NextDouble() < 0.25)
702 { 775 return;
703 SceneObjectPart selectedTree = ((SceneObjectGroup)m_scene.Entities[tree]).RootPart;
704 double selectedTreeScale = Math.Sqrt(Math.Pow(selectedTree.Scale.X, 2) +
705 Math.Pow(selectedTree.Scale.Y, 2) +
706 Math.Pow(selectedTree.Scale.Z, 2));
707
708 foreach (UUID picktree in copse.m_trees)
709 {
710 if (picktree != tree)
711 {
712 SceneObjectPart pickedTree = ((SceneObjectGroup)m_scene.Entities[picktree]).RootPart;
713
714 double pickedTreeScale = Math.Sqrt(Math.Pow(pickedTree.Scale.X, 2) +
715 Math.Pow(pickedTree.Scale.Y, 2) +
716 Math.Pow(pickedTree.Scale.Z, 2));
717 776
718 double pickedTreeDistance = Vector3.Distance(pickedTree.AbsolutePosition, selectedTree.AbsolutePosition); 777 int maxbdeaths = copse.m_trees.Count - (int)(copse.m_tree_quantity * .98f) ;
778 if(maxbdeaths < 1)
779 return;
719 780
720 killLikelyhood += (selectedTreeScale / (pickedTreeScale * pickedTreeDistance)) * 0.1; 781 float odds;
721 } 782 float scale = 1.0f / copse.m_maximum_scale.Z;
722 }
723 783
724 if (Util.RandomClass.NextDouble() < killLikelyhood) 784 int ntries = maxbdeaths * 4;
725 { 785 while(ntries-- > 0 )
726 // Delete tree and alert clients (not silent) 786 {
727 m_scene.DeleteSceneObject(selectedTree.ParentGroup, false); 787 int next = 0;
728 copse.m_trees.Remove(selectedTree.ParentGroup.UUID); 788 if (copse.m_trees.Count > 1)
729 break; 789 next = Util.RandomClass.Next(copse.m_trees.Count - 1);
730 } 790 UUID tree = copse.m_trees[next];
791 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(tree);
792 if (sog != null && !sog.IsDeleted)
793 {
794 if(m_allowGrow)
795 {
796 odds = sog.RootPart.Scale.Z * scale;
797 odds = odds * odds * odds;
798 odds *= (float)Util.RandomClass.NextDouble();
731 } 799 }
732 else 800 else
733 { 801 {
734 m_log.DebugFormat("[TREES]: Tree not in scene {0}", tree); 802 odds = (float)Util.RandomClass.NextDouble();
803 odds = odds * odds * odds;
735 } 804 }
805
806 if(odds > 0.9f)
807 {
808 m_scene.DeleteSceneObject(sog, false);
809 if(maxbdeaths <= 0)
810 break;
811 }
812 }
813 else
814 {
815 copse.m_trees.Remove(tree);
816 if(copse.m_trees.Count - (int)(copse.m_tree_quantity * .98f) <= 0 )
817 break;
736 } 818 }
737 } 819 }
738 } 820 }
739 } 821 }
740 822
741 private void SpawnChild(Copse copse, SceneObjectPart s_tree) 823 private void SpawnChild(Copse copse, SceneObjectPart s_tree, bool low)
742 { 824 {
743 Vector3 position = new Vector3(); 825 Vector3 position = new Vector3();
744 826
745 double randX = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3); 827 float randX = copse.m_maximum_scale.X * 1.25f;
746 double randY = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3); 828 float randY = copse.m_maximum_scale.Y * 1.25f;
747 829
830 float r = (float)Util.RandomClass.NextDouble();
831 randX *= 2.0f * r - 1.0f;
748 position.X = s_tree.AbsolutePosition.X + (float)randX; 832 position.X = s_tree.AbsolutePosition.X + (float)randX;
833
834 r = (float)Util.RandomClass.NextDouble();
835 randY *= 2.0f * r - 1.0f;
749 position.Y = s_tree.AbsolutePosition.Y + (float)randY; 836 position.Y = s_tree.AbsolutePosition.Y + (float)randY;
750 837
751 if (position.X <= (m_scene.RegionInfo.RegionSizeX - 1) && position.X >= 0 && 838 if (position.X > (m_scene.RegionInfo.RegionSizeX - 1) || position.X <= 0 ||
752 position.Y <= (m_scene.RegionInfo.RegionSizeY - 1) && position.Y >= 0 && 839 position.Y > (m_scene.RegionInfo.RegionSizeY - 1) || position.Y <= 0)
753 Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range) 840 return;
754 {
755 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
756 841
757 CreateTree(uuid, copse, position); 842 randX = position.X - copse.m_seed_point.X;
758 } 843 randX *= randX;
844 randY = position.Y - copse.m_seed_point.Y;
845 randY *= randY;
846 randX += randY;
847
848 if(randX > copse.m_range * copse.m_range)
849 return;
850
851 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
852 CreateTree(uuid, copse, position, low);
759 } 853 }
760 854
761 private void CreateTree(UUID uuid, Copse copse, Vector3 position) 855 private void CreateTree(UUID uuid, Copse copse, Vector3 position, bool randomScale)
762 { 856 {
763
764 position.Z = (float)m_scene.Heightmap[(int)position.X, (int)position.Y]; 857 position.Z = (float)m_scene.Heightmap[(int)position.X, (int)position.Y];
765 if (position.Z >= copse.m_treeline_low && position.Z <= copse.m_treeline_high) 858 if (position.Z < copse.m_treeline_low || position.Z > copse.m_treeline_high)
766 { 859 return;
767 SceneObjectGroup tree = AddTree(uuid, UUID.Zero, copse.m_initial_scale, Quaternion.Identity, position, copse.m_tree_type, false);
768 860
769 tree.Name = copse.ToString(); 861 Vector3 scale = copse.m_initial_scale;
770 copse.m_trees.Add(tree.UUID); 862 if(randomScale)
771 tree.SendGroupFullUpdate(); 863 {
864 try
865 {
866 float t;
867 float r = (float)Util.RandomClass.NextDouble();
868 r *= (float)Util.RandomClass.NextDouble();
869 r *= (float)Util.RandomClass.NextDouble();
870
871 t = copse.m_maximum_scale.X / copse.m_initial_scale.X;
872 if(t < 1.0)
873 t = 1 / t;
874 t = t * r + 1.0f;
875 scale.X *= t;
876
877 t = copse.m_maximum_scale.Y / copse.m_initial_scale.Y;
878 if(t < 1.0)
879 t = 1 / t;
880 t = t * r + 1.0f;
881 scale.Y *= t;
882
883 t = copse.m_maximum_scale.Z / copse.m_initial_scale.Z;
884 if(t < 1.0)
885 t = 1 / t;
886 t = t * r + 1.0f;
887 scale.Z *= t;
888 }
889 catch
890 {
891 scale = copse.m_initial_scale;
892 }
772 } 893 }
894
895 SceneObjectGroup tree = AddTree(uuid, UUID.Zero, scale, Quaternion.Identity, position, copse.m_tree_type, false);
896 tree.Name = copse.ToString();
897 copse.m_trees.Add(tree.UUID);
898 tree.RootPart.ScheduleFullUpdate();
773 } 899 }
774 900
775 private void CalculateTrees_Elapsed(object sender, ElapsedEventArgs e) 901 private void CalculateTrees_Elapsed(object sender, ElapsedEventArgs e)
776 { 902 {
777 growTrees(); 903 if(!m_scene.IsRunning)
778 seedTrees(); 904 return;
779 killTrees(); 905
906 if(Monitor.TryEnter(mylock))
907 {
908 try
909 {
910 if(m_scene.LoginsEnabled )
911 {
912 growTrees();
913 seedTrees();
914 killTrees();
915 }
916 }
917 catch { }
918 if(CalculateTrees != null)
919 CalculateTrees.Start();
920 Monitor.Exit(mylock);
921 }
780 } 922 }
781 } 923 }
782} 924}