aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/OptionalModules')
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs628
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs219
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs887
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs424
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs604
-rwxr-xr-xOpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeServer.py130
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs292
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs202
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/AuraMetaEntity.cs161
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/BeamMetaEntity.cs139
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/CMController.cs757
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/CMEntityCollection.cs193
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs362
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/CMView.cs206
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/ContentManagementEntity.cs383
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/ContentManagementModule.cs163
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/FileSystemDatabase.cs317
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/GitDatabase.cs167
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/IContentDatabase.cs94
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs274
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/PointMetaEntity.cs116
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/README52
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/SceneObjectGroupDiff.cs218
-rw-r--r--OpenSim/Region/OptionalModules/Grid/Interregion/IInterregionModule.cs43
-rw-r--r--OpenSim/Region/OptionalModules/Grid/Interregion/InterregionModule.cs199
-rw-r--r--OpenSim/Region/OptionalModules/Grid/Interregion/RemotingObject.cs77
-rw-r--r--OpenSim/Region/OptionalModules/Python/PythonAPI/Console.cs48
-rw-r--r--OpenSim/Region/OptionalModules/Python/PythonModule.cs71
-rw-r--r--OpenSim/Region/OptionalModules/README9
-rw-r--r--OpenSim/Region/OptionalModules/SvnSerialiser/Properties/AssemblyInfo.cs62
-rw-r--r--OpenSim/Region/OptionalModules/SvnSerialiser/SvnBackupModule.cs396
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs1060
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs68
-rw-r--r--OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs304
34 files changed, 9325 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
new file mode 100644
index 0000000..167f0cc
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
@@ -0,0 +1,628 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Text.RegularExpressions;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.Region.OptionalModules.Avatar.Chat
39{
40
41 // An instance of this class exists for each unique combination of
42 // IRC chat interface characteristics, as determined by the supplied
43 // configuration file.
44
45 internal class ChannelState
46 {
47
48 private static readonly ILog m_log =
49 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private static Regex arg = new Regex(@"\[[^\[\]]*\]");
52 private static int _idk_ = 0;
53 private static int DEBUG_CHANNEL = 2147483647;
54
55 // These are the IRC Connector configurable parameters with hard-wired
56 // default values (retained for compatability).
57
58 internal string Server = null;
59 internal string Password = null;
60 internal string IrcChannel = null;
61 internal string BaseNickname = "OSimBot";
62 internal uint Port = 6667;
63 internal string User = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
64
65 internal bool ClientReporting = true;
66 internal bool RelayChat = true;
67 internal bool RelayPrivateChannels = false;
68 internal int RelayChannel = 1;
69 internal List<int> ValidInWorldChannels = new List<int>();
70
71 // Connector agnostic parameters. These values are NOT shared with the
72 // connector and do not differentiate at an IRC level
73
74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}";
75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}";
76 internal int RelayChannelOut = -1;
77 internal bool RandomizeNickname = true;
78 internal bool CommandsEnabled = false;
79 internal int CommandChannel = -1;
80 internal int ConnectDelay = 10;
81 internal int PingDelay = 15;
82 internal string DefaultZone = "Sim";
83
84 internal string _accessPassword = String.Empty;
85 internal Regex AccessPasswordRegex = null;
86 internal string AccessPassword
87 {
88 get { return _accessPassword; }
89 set
90 {
91 _accessPassword = value;
92 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword),
93 RegexOptions.Compiled);
94 }
95 }
96
97
98
99 // IRC connector reference
100
101 internal IRCConnector irc = null;
102
103 internal int idn = _idk_++;
104
105 // List of regions dependent upon this connection
106
107 internal List<RegionState> clientregions = new List<RegionState>();
108
109 // Needed by OpenChannel
110
111 internal ChannelState()
112 {
113 }
114
115 // This constructor is used by the Update* methods. A copy of the
116 // existing channel state is created, and distinguishing characteristics
117 // are copied across.
118
119 internal ChannelState(ChannelState model)
120 {
121 Server = model.Server;
122 Password = model.Password;
123 IrcChannel = model.IrcChannel;
124 Port = model.Port;
125 BaseNickname = model.BaseNickname;
126 RandomizeNickname = model.RandomizeNickname;
127 User = model.User;
128 CommandsEnabled = model.CommandsEnabled;
129 CommandChannel = model.CommandChannel;
130 RelayChat = model.RelayChat;
131 RelayPrivateChannels = model.RelayPrivateChannels;
132 RelayChannelOut = model.RelayChannelOut;
133 RelayChannel = model.RelayChannel;
134 ValidInWorldChannels = model.ValidInWorldChannels;
135 PrivateMessageFormat = model.PrivateMessageFormat;
136 NoticeMessageFormat = model.NoticeMessageFormat;
137 ClientReporting = model.ClientReporting;
138 AccessPassword = model.AccessPassword;
139 DefaultZone = model.DefaultZone;
140 ConnectDelay = model.ConnectDelay;
141 PingDelay = model.PingDelay;
142 }
143
144 // Read the configuration file, performing variable substitution and any
145 // necessary aliasing. See accompanying documentation for how this works.
146 // If you don't need variables, then this works exactly as before.
147 // If either channel or server are not specified, the request fails.
148
149 internal static void OpenChannel(RegionState rs, IConfig config)
150 {
151
152 // Create a new instance of a channel. This may not actually
153 // get used if an equivalent channel already exists.
154
155 ChannelState cs = new ChannelState();
156
157 // Read in the configuration file and filter everything for variable
158 // subsititution.
159
160 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region);
161
162 cs.Server = Substitute(rs, config.GetString("server", null));
163 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server);
164 cs.Password = Substitute(rs, config.GetString("password", null));
165 // probably not a good idea to put a password in the log file
166 cs.IrcChannel = Substitute(rs, config.GetString("channel", null));
167 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel);
168 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port))));
169 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port);
170 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname));
171 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname);
172 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname))));
173 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname))));
175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
176 cs.User = Substitute(rs, config.GetString("username", cs.User));
177 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User);
178 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled))));
179 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled);
180 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel))));
181 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel))));
183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
184 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat))));
185 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat);
186 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels))));
187 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels))));
189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
190 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut))));
191 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut);
192 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel))));
193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel))));
195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
196 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat));
197 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat);
198 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat));
199 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat);
200 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting?"1":"0"))) > 0;
201 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
202 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting))));
203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
204 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone));
205 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone);
206 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay))));
207 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay);
208 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay))));
209 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay);
210 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword));
211 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword);
212
213
214 // Fail if fundamental information is still missing
215
216 if (cs.Server == null || cs.IrcChannel == null || cs.BaseNickname == null || cs.User == null)
217 throw new Exception(String.Format("[IRC-Channel-{0}] Invalid configuration for region {1}", cs.idn, rs.Region));
218
219 m_log.InfoFormat("[IRC-Channel-{0}] Configuration for Region {1} is valid", cs.idn, rs.Region);
220 m_log.InfoFormat("[IRC-Channel-{0}] Server = {1}", cs.idn, cs.Server);
221 m_log.InfoFormat("[IRC-Channel-{0}] Channel = {1}", cs.idn, cs.IrcChannel);
222 m_log.InfoFormat("[IRC-Channel-{0}] Port = {1}", cs.idn, cs.Port);
223 m_log.InfoFormat("[IRC-Channel-{0}] Nickname = {1}", cs.idn, cs.BaseNickname);
224 m_log.InfoFormat("[IRC-Channel-{0}] User = {1}", cs.idn, cs.User);
225
226 // Set the channel state for this region
227
228 if (cs.RelayChat)
229 {
230 cs.ValidInWorldChannels.Add(0);
231 cs.ValidInWorldChannels.Add(DEBUG_CHANNEL);
232 }
233
234 if (cs.RelayPrivateChannels)
235 cs.ValidInWorldChannels.Add(cs.RelayChannelOut);
236
237 rs.cs = Integrate(rs, cs);
238
239 }
240
241 // An initialized channel state instance is passed in. If an identical
242 // channel state instance already exists, then the existing instance
243 // is used to replace the supplied value.
244 // If the instance matches with respect to IRC, then the underlying
245 // IRCConnector is assigned to the supplied channel state and the
246 // updated value is returned.
247 // If there is no match, then the supplied instance is completed by
248 // creating and assigning an instance of an IRC connector.
249
250 private static ChannelState Integrate(RegionState rs, ChannelState p_cs)
251 {
252
253 ChannelState cs = p_cs;
254
255 // Check to see if we have an existing server/channel setup that can be used
256 // In the absence of variable substitution this will always resolve to the
257 // same ChannelState instance, and the table will only contains a single
258 // entry, so the performance considerations for the existing behavior are
259 // zero. Only the IRC connector is shared, the ChannelState still contains
260 // values that, while independent of the IRC connetion, do still distinguish
261 // this region's behavior.
262
263 lock (IRCBridgeModule.m_channels)
264 {
265
266 foreach (ChannelState xcs in IRCBridgeModule.m_channels)
267 {
268 if (cs.IsAPerfectMatchFor(xcs))
269 {
270 m_log.DebugFormat("[IRC-Channel-{0}] Channel state matched", cs.idn);
271 cs = xcs;
272 break;
273 }
274 if (cs.IsAConnectionMatchFor(xcs))
275 {
276 m_log.DebugFormat("[IRC-Channel-{0}] Channel matched", cs.idn);
277 cs.irc = xcs.irc;
278 break;
279 }
280 }
281
282 }
283
284 // No entry was found, so this is going to be a new entry.
285
286 if (cs.irc == null)
287 {
288
289 m_log.DebugFormat("[IRC-Channel-{0}] New channel required", cs.idn);
290
291 if ((cs.irc = new IRCConnector(cs)) != null)
292 {
293
294 IRCBridgeModule.m_channels.Add(cs);
295
296 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}",
297 cs.idn, rs.Region, cs.DefaultZone,
298 cs.CommandsEnabled ? "enabled" : "not enabled",
299 cs.RelayPrivateChannels ? "relayed" : "not relayed");
300 }
301 else
302 {
303 string txt = String.Format("[IRC-Channel-{0}] Region {1} failed to connect to channel {2} on server {3}:{4}",
304 cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
305 m_log.Error(txt);
306 throw new Exception(txt);
307 }
308 }
309 else
310 {
311 m_log.InfoFormat("[IRC-Channel-{0}] Region {1} reusing existing connection to channel {2} on server {3}:{4}",
312 cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
313 }
314
315 m_log.InfoFormat("[IRC-Channel-{0}] Region {1} associated with channel {2} on server {3}:{4}",
316 cs.idn, rs.Region, cs.IrcChannel, cs.Server, cs.Port);
317
318 // We're finally ready to commit ourselves
319
320
321 return cs;
322
323 }
324
325 // These routines allow differentiating changes to
326 // the underlying channel state. If necessary, a
327 // new channel state will be created.
328
329 internal ChannelState UpdateServer(RegionState rs, string server)
330 {
331 RemoveRegion(rs);
332 ChannelState cs = new ChannelState(this);
333 cs.Server = server;
334 cs = Integrate(rs, cs);
335 cs.AddRegion(rs);
336 return cs;
337 }
338
339 internal ChannelState UpdatePort(RegionState rs, string port)
340 {
341 RemoveRegion(rs);
342 ChannelState cs = new ChannelState(this);
343 cs.Port = Convert.ToUInt32(port);
344 cs = Integrate(rs, cs);
345 cs.AddRegion(rs);
346 return cs;
347 }
348
349 internal ChannelState UpdateChannel(RegionState rs, string channel)
350 {
351 RemoveRegion(rs);
352 ChannelState cs = new ChannelState(this);
353 cs.IrcChannel = channel;
354 cs = Integrate(rs, cs);
355 cs.AddRegion(rs);
356 return cs;
357 }
358
359 internal ChannelState UpdateNickname(RegionState rs, string nickname)
360 {
361 RemoveRegion(rs);
362 ChannelState cs = new ChannelState(this);
363 cs.BaseNickname = nickname;
364 cs = Integrate(rs, cs);
365 cs.AddRegion(rs);
366 return cs;
367 }
368
369 internal ChannelState UpdateClientReporting(RegionState rs, string cr)
370 {
371 RemoveRegion(rs);
372 ChannelState cs = new ChannelState(this);
373 cs.ClientReporting = Convert.ToBoolean(cr);
374 cs = Integrate(rs, cs);
375 cs.AddRegion(rs);
376 return cs;
377 }
378
379 internal ChannelState UpdateRelayIn(RegionState rs, string channel)
380 {
381 RemoveRegion(rs);
382 ChannelState cs = new ChannelState(this);
383 cs.RelayChannel = Convert.ToInt32(channel);
384 cs = Integrate(rs, cs);
385 cs.AddRegion(rs);
386 return cs;
387 }
388
389 internal ChannelState UpdateRelayOut(RegionState rs, string channel)
390 {
391 RemoveRegion(rs);
392 ChannelState cs = new ChannelState(this);
393 cs.RelayChannelOut = Convert.ToInt32(channel);
394 cs = Integrate(rs, cs);
395 cs.AddRegion(rs);
396 return cs;
397 }
398
399 // Determine whether or not this is a 'new' channel. Only those
400 // attributes that uniquely distinguish an IRC connection should
401 // be included here (and only those attributes should really be
402 // in the ChannelState structure)
403
404 private bool IsAConnectionMatchFor(ChannelState cs)
405 {
406 return (
407 Server == cs.Server &&
408 IrcChannel == cs.IrcChannel &&
409 Port == cs.Port &&
410 BaseNickname == cs.BaseNickname &&
411 User == cs.User
412 );
413 }
414
415 // This level of obsessive matching allows us to produce
416 // a minimal overhead int he case of a server which does
417 // need to differentiate IRC at a region level.
418
419 private bool IsAPerfectMatchFor(ChannelState cs)
420 {
421 return ( IsAConnectionMatchFor(cs) &&
422 RelayChannelOut == cs.RelayChannelOut &&
423 PrivateMessageFormat == cs.PrivateMessageFormat &&
424 NoticeMessageFormat == cs.NoticeMessageFormat &&
425 RandomizeNickname == cs.RandomizeNickname &&
426 AccessPassword == cs.AccessPassword &&
427 CommandsEnabled == cs.CommandsEnabled &&
428 CommandChannel == cs.CommandChannel &&
429 DefaultZone == cs.DefaultZone &&
430 RelayPrivateChannels == cs.RelayPrivateChannels &&
431 RelayChannel == cs.RelayChannel &&
432 RelayChat == cs.RelayChat &&
433 ClientReporting == cs.ClientReporting
434 );
435 }
436
437 // This function implements the variable substitution mechanism
438 // for the configuration values. Each string read from the
439 // configuration file is scanned for '[...]' enclosures. Each
440 // one that is found is replaced by either a runtime variable
441 // (%xxx) or an existing configuration key. When no further
442 // substitution is possible, the remaining string is returned
443 // to the caller. This allows for arbitrarily nested
444 // enclosures.
445
446 private static string Substitute(RegionState rs, string instr)
447 {
448
449 string result = instr;
450
451 if (result == null || result.Length == 0)
452 return result;
453
454 // Repeatedly scan the string until all possible
455 // substitutions have been performed.
456
457 // m_log.DebugFormat("[IRC-Channel] Parse[1]: {0}", result);
458
459 while (arg.IsMatch(result))
460 {
461
462 string vvar = arg.Match(result).ToString();
463 string var = vvar.Substring(1,vvar.Length-2).Trim();
464
465 switch (var.ToLower())
466 {
467 case "%region" :
468 result = result.Replace(vvar, rs.Region);
469 break;
470 case "%host" :
471 result = result.Replace(vvar, rs.Host);
472 break;
473 case "%master1" :
474 result = result.Replace(vvar, rs.MA1);
475 break;
476 case "%master2" :
477 result = result.Replace(vvar, rs.MA2);
478 break;
479 case "%locx" :
480 result = result.Replace(vvar, rs.LocX);
481 break;
482 case "%locy" :
483 result = result.Replace(vvar, rs.LocY);
484 break;
485 case "%k" :
486 result = result.Replace(vvar, rs.IDK);
487 break;
488 default :
489 result = result.Replace(vvar, rs.config.GetString(var,var));
490 break;
491 }
492 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result);
493 }
494
495 // m_log.DebugFormat("[IRC-Channel] Parse[3]: {0}", result);
496 return result;
497
498 }
499
500 public void Close()
501 {
502 m_log.InfoFormat("[IRC-Channel-{0}] Closing channel <{1}> to server <{2}:{3}>",
503 idn, IrcChannel, Server, Port);
504 m_log.InfoFormat("[IRC-Channel-{0}] There are {1} active clients",
505 idn, clientregions.Count);
506 irc.Close();
507 }
508
509 public void Open()
510 {
511 m_log.InfoFormat("[IRC-Channel-{0}] Opening channel <{1}> to server <{2}:{3}>",
512 idn, IrcChannel, Server, Port);
513
514 irc.Open();
515
516 }
517
518 // These are called by each region that attaches to this channel. The call affects
519 // only the relationship of the region with the channel. Not the channel to IRC
520 // relationship (unless it is closed and we want it open).
521
522 public void Open(RegionState rs)
523 {
524 AddRegion(rs);
525 Open();
526 }
527
528 // Close is called to ensure that the IRC session is terminated if this is the
529 // only client.
530
531 public void Close(RegionState rs)
532 {
533 RemoveRegion(rs);
534 lock (IRCBridgeModule.m_channels)
535 {
536 if (clientregions.Count == 0)
537 {
538 Close();
539 IRCBridgeModule.m_channels.Remove(this);
540 m_log.InfoFormat("[IRC-Channel-{0}] Region {1} is last user of channel <{2}> to server <{3}:{4}>",
541 idn, rs.Region, IrcChannel, Server, Port);
542 m_log.InfoFormat("[IRC-Channel-{0}] Removed", idn);
543 }
544 }
545 }
546
547 // Add a client region to this channel if it is not already known
548
549 public void AddRegion(RegionState rs)
550 {
551 m_log.InfoFormat("[IRC-Channel-{0}] Adding region {1} to channel <{2}> to server <{3}:{4}>",
552 idn, rs.Region, IrcChannel, Server, Port);
553 if (!clientregions.Contains(rs))
554 {
555 clientregions.Add(rs);
556 lock (irc) irc.depends++;
557 }
558 }
559
560 // Remove a client region from the channel. If this is the last
561 // region, then clean up the channel. The connector will clean itself
562 // up if it finds itself about to be GC'd.
563
564 public void RemoveRegion(RegionState rs)
565 {
566
567 m_log.InfoFormat("[IRC-Channel-{0}] Removing region {1} from channel <{2} to server <{3}:{4}>",
568 idn, rs.Region, IrcChannel, Server, Port);
569
570 if (clientregions.Contains(rs))
571 {
572 clientregions.Remove(rs);
573 lock (irc) irc.depends--;
574 }
575
576 }
577
578 // This function is lifted from the IRCConnector because it
579 // contains information that is not differentiating from an
580 // IRC point-of-view.
581
582 public static void OSChat(IRCConnector p_irc, OSChatMessage c, bool cmsg)
583 {
584
585 // m_log.DebugFormat("[IRC-OSCHAT] from {0}:{1}", p_irc.Server, p_irc.IrcChannel);
586
587 try
588 {
589
590 // Scan through the set of unique channel configuration for those
591 // that belong to this connector. And then forward the message to
592 // all regions known to those channels.
593 // Note that this code is responsible for completing some of the
594 // settings for the inbound OSChatMessage
595
596 lock (IRCBridgeModule.m_channels)
597 {
598 foreach (ChannelState cs in IRCBridgeModule.m_channels)
599 {
600 if ( p_irc == cs.irc)
601 {
602
603 // This non-IRC differentiator moved to here
604
605 if (cmsg && !cs.ClientReporting)
606 continue;
607
608 // This non-IRC differentiator moved to here
609
610 c.Channel = (cs.RelayPrivateChannels ? cs.RelayChannel : 0);
611
612 foreach (RegionState region in cs.clientregions)
613 {
614 region.OSChat(cs.irc, c);
615 }
616
617 }
618 }
619 }
620 }
621 catch (Exception ex)
622 {
623 m_log.ErrorFormat("[IRC-OSCHAT]: BroadcastSim Exception: {0}", ex.Message);
624 m_log.Debug(ex);
625 }
626 }
627 }
628}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
new file mode 100644
index 0000000..0facc14
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
@@ -0,0 +1,219 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.OptionalModules.Avatar.Chat
40{
41 public class IRCBridgeModule : IRegionModule
42 {
43 private static readonly ILog m_log =
44 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 internal static bool configured = false;
47 internal static bool enabled = false;
48 internal static IConfig m_config = null;
49
50 internal static List<ChannelState> m_channels = new List<ChannelState>();
51 internal static List<RegionState> m_regions = new List<RegionState>();
52
53 internal static string password = String.Empty;
54
55 internal RegionState region = null;
56
57 #region IRegionModule Members
58
59 public string Name
60 {
61 get { return "IRCBridgeModule"; }
62 }
63
64 public bool IsSharedModule
65 {
66 get { return false; }
67 }
68
69 public void Initialise(Scene scene, IConfigSource config)
70 {
71 // Do a once-only scan of the configuration file to make
72 // sure it's basically intact.
73
74 if (!configured)
75 {
76 configured = true;
77
78 try
79 {
80 if ((m_config = config.Configs["IRC"]) == null)
81 {
82 m_log.InfoFormat("[IRC-Bridge] module not configured");
83 return;
84 }
85
86 if (!m_config.GetBoolean("enabled", false))
87 {
88 m_log.InfoFormat("[IRC-Bridge] module disabled in configuration");
89 return;
90 }
91 }
92 catch (Exception e)
93 {
94 m_log.ErrorFormat("[IRC-Bridge] configuration failed : {0}", e.Message);
95 return;
96 }
97
98 enabled = true;
99
100 if (config.Configs["RemoteAdmin"] != null)
101 {
102 password = config.Configs["RemoteAdmin"].GetString("access_password", password);
103 scene.CommsManager.HttpServer.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false);
104 }
105 }
106
107 // Iff the IRC bridge is enabled, then each new region may be
108 // connected to IRC. But it should NOT be obligatory (and it
109 // is not).
110 // We have to do ALL of the startup here because PostInitialize
111 // is not called when a region gets created in-flight from the
112 // command line.
113
114 if (enabled)
115 {
116 try
117 {
118 m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName);
119 region = new RegionState(scene, m_config);
120 lock (m_regions) m_regions.Add(region);
121 region.Open();
122 }
123 catch (Exception e)
124 {
125 m_log.WarnFormat("[IRC-Bridge] Region {0} not connected to IRC : {1}", scene.RegionInfo.RegionName, e.Message);
126 m_log.Debug(e);
127 }
128 }
129 else
130 {
131 m_log.WarnFormat("[IRC-Bridge] Not enabled. Connect for region {0} ignored", scene.RegionInfo.RegionName);
132 }
133 }
134
135 // This module can be called in-flight in which case PostInitialize
136 // is not called following Initialize. So no use is made of this
137 // call.
138
139 public void PostInitialise()
140 {
141 }
142
143 // Called immediately before the region module is unloaded. Cleanup
144 // the region.
145
146 public void Close()
147 {
148 if (!enabled)
149 return;
150
151 region.Close();
152 lock (m_regions) m_regions.Remove(region);
153 }
154
155 #endregion
156
157 public static XmlRpcResponse XmlRpcAdminMethod(XmlRpcRequest request)
158 {
159 m_log.Info("[IRC-Bridge]: XML RPC Admin Entry");
160
161 XmlRpcResponse response = new XmlRpcResponse();
162 Hashtable responseData = new Hashtable();
163
164 try
165 {
166 Hashtable requestData = (Hashtable)request.Params[0];
167 bool found = false;
168 string region = String.Empty;
169
170 if (password != String.Empty)
171 {
172 if (!requestData.ContainsKey("password"))
173 throw new Exception("Invalid request");
174 if ((string)requestData["password"] != password)
175 throw new Exception("Invalid request");
176 }
177
178 if (!requestData.ContainsKey("region"))
179 throw new Exception("No region name specified");
180 region = (string)requestData["region"];
181
182 foreach (RegionState rs in m_regions)
183 {
184 if (rs.Region == region)
185 {
186 responseData["server"] = rs.cs.Server;
187 responseData["port"] = (int)rs.cs.Port;
188 responseData["user"] = rs.cs.User;
189 responseData["channel"] = rs.cs.IrcChannel;
190 responseData["enabled"] = rs.cs.irc.Enabled;
191 responseData["connected"] = rs.cs.irc.Connected;
192 responseData["nickname"] = rs.cs.irc.Nick;
193 found = true;
194 break;
195 }
196 }
197
198 if (!found) throw new Exception(String.Format("Region <{0}> not found", region));
199
200 responseData["success"] = true;
201 }
202 catch (Exception e)
203 {
204 m_log.InfoFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message);
205
206 responseData["success"] = "false";
207 responseData["error"] = e.Message;
208 }
209 finally
210 {
211 response.Value = responseData;
212 }
213
214 m_log.Debug("[IRC-Bridge]: XML RPC Admin Exit");
215
216 return response;
217 }
218 }
219}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
new file mode 100644
index 0000000..f5c324d
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
@@ -0,0 +1,887 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Timers;
30using System.Collections.Generic;
31using System.IO;
32using System.Net.Sockets;
33using System.Reflection;
34using System.Text.RegularExpressions;
35using System.Threading;
36using OpenMetaverse;
37using log4net;
38using Nini.Config;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42
43namespace OpenSim.Region.OptionalModules.Avatar.Chat
44{
45 public class IRCConnector
46 {
47
48 #region Global (static) state
49
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 // Local constants
53
54 private static readonly Vector3 CenterOfRegion = new Vector3(128, 128, 20);
55 private static readonly char[] CS_SPACE = { ' ' };
56
57 private const int WD_INTERVAL = 1000; // base watchdog interval
58 private static int PING_PERIOD = 15; // WD intervals per PING
59 private static int ICCD_PERIOD = 10; // WD intervals between Connects
60 private static int L_TIMEOUT = 25; // Login time out interval
61
62 private static int _idk_ = 0; // core connector identifier
63 private static int _pdk_ = 0; // ping interval counter
64 private static int _icc_ = 0; // IRC connect counter
65
66 // List of configured connectors
67
68 private static List<IRCConnector> m_connectors = new List<IRCConnector>();
69
70 // Watchdog state
71
72 private static System.Timers.Timer m_watchdog = null;
73
74 static IRCConnector()
75 {
76 m_log.DebugFormat("[IRC-Connector]: Static initialization started");
77 m_watchdog = new System.Timers.Timer(WD_INTERVAL);
78 m_watchdog.Elapsed += new ElapsedEventHandler(WatchdogHandler);
79 m_watchdog.AutoReset = true;
80 m_watchdog.Start();
81 m_log.DebugFormat("[IRC-Connector]: Static initialization complete");
82 }
83
84 #endregion
85
86 #region Instance state
87
88 // Connector identity
89
90 internal int idn = _idk_++;
91
92 // How many regions depend upon this connection
93 // This count is updated by the ChannelState object and reflects the sum
94 // of the region clients associated with the set of associated channel
95 // state instances. That's why it cannot be managed here.
96
97 internal int depends = 0;
98
99 // Working threads
100
101 private Thread m_listener = null;
102
103 private Object msyncConnect = new Object();
104
105 internal bool m_randomizeNick = true; // add random suffix
106 internal string m_baseNick = null; // base name for randomizing
107 internal string m_nick = null; // effective nickname
108
109 public string Nick // Public property
110 {
111 get { return m_nick; }
112 set { m_nick = value; }
113 }
114
115 private bool m_enabled = false; // connector enablement
116 public bool Enabled
117 {
118 get { return m_enabled; }
119 }
120
121 private bool m_connected = false; // connection status
122 private bool m_pending = false; // login disposition
123 private int m_timeout = L_TIMEOUT; // login timeout counter
124 public bool Connected
125 {
126 get { return m_connected; }
127 }
128
129 private string m_ircChannel; // associated channel id
130 public string IrcChannel
131 {
132 get { return m_ircChannel; }
133 set { m_ircChannel = value; }
134 }
135
136 private uint m_port = 6667; // session port
137 public uint Port
138 {
139 get { return m_port; }
140 set { m_port = value; }
141 }
142
143 private string m_server = null; // IRC server name
144 public string Server
145 {
146 get { return m_server; }
147 set { m_server = value; }
148 }
149 private string m_password = null;
150 public string Password
151 {
152 get { return m_password; }
153 set { m_password = value; }
154 }
155
156 private string m_user = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
157 public string User
158 {
159 get { return m_user; }
160 }
161
162 // Network interface
163
164 private TcpClient m_tcp;
165 private NetworkStream m_stream = null;
166 private StreamReader m_reader;
167 private StreamWriter m_writer;
168
169 // Channel characteristic info (if available)
170
171 internal string usermod = String.Empty;
172 internal string chanmod = String.Empty;
173 internal string version = String.Empty;
174 internal bool motd = false;
175
176 #endregion
177
178 #region connector instance management
179
180 internal IRCConnector(ChannelState cs)
181 {
182
183 // Prepare network interface
184
185 m_tcp = null;
186 m_writer = null;
187 m_reader = null;
188
189 // Setup IRC session parameters
190
191 m_server = cs.Server;
192 m_password = cs.Password;
193 m_baseNick = cs.BaseNickname;
194 m_randomizeNick = cs.RandomizeNickname;
195 m_ircChannel = cs.IrcChannel;
196 m_port = cs.Port;
197 m_user = cs.User;
198
199 if (m_watchdog == null)
200 {
201 // Non-differentiating
202
203 ICCD_PERIOD = cs.ConnectDelay;
204 PING_PERIOD = cs.PingDelay;
205
206 // Smaller values are not reasonable
207
208 if (ICCD_PERIOD < 5)
209 ICCD_PERIOD = 5;
210
211 if (PING_PERIOD < 5)
212 PING_PERIOD = 5;
213
214 _icc_ = ICCD_PERIOD; // get started right away!
215
216 }
217
218 // The last line of defense
219
220 if (m_server == null || m_baseNick == null || m_ircChannel == null || m_user == null)
221 throw new Exception("Invalid connector configuration");
222
223 // Generate an initial nickname if randomizing is enabled
224
225 if (m_randomizeNick)
226 {
227 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
228 }
229
230 // Add the newly created connector to the known connectors list
231
232 m_connectors.Add(this);
233
234 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);
235
236 }
237
238 ~IRCConnector()
239 {
240 m_watchdog.Stop();
241 Close();
242 }
243
244 // Mark the connector as connectable. Harmless if already enabled.
245
246 public void Open()
247 {
248 if (!m_enabled)
249 {
250
251 m_connectors.Add(this);
252 m_enabled = true;
253
254 if (!Connected)
255 {
256 Connect();
257 }
258
259 }
260 }
261
262 // Only close the connector if the dependency count is zero.
263
264 public void Close()
265 {
266
267 m_log.InfoFormat("[IRC-Connector-{0}] Closing", idn);
268
269 lock (msyncConnect)
270 {
271
272 if ((depends == 0) && Enabled)
273 {
274
275 m_enabled = false;
276
277 if (Connected)
278 {
279 m_log.DebugFormat("[IRC-Connector-{0}] Closing interface", idn);
280
281 // Cleanup the IRC session
282
283 try
284 {
285 m_writer.WriteLine(String.Format("QUIT :{0} to {1} wormhole to {2} closing",
286 m_nick, m_ircChannel, m_server));
287 m_writer.Flush();
288 }
289 catch (Exception) {}
290
291
292 m_connected = false;
293
294 try { m_writer.Close(); } catch (Exception) {}
295 try { m_reader.Close(); } catch (Exception) {}
296 try { m_stream.Close(); } catch (Exception) {}
297 try { m_tcp.Close(); } catch (Exception) {}
298
299 }
300
301 m_connectors.Remove(this);
302
303 }
304 }
305
306 m_log.InfoFormat("[IRC-Connector-{0}] Closed", idn);
307
308 }
309
310 #endregion
311
312 #region session management
313
314 // Connect to the IRC server. A connector should always be connected, once enabled
315
316 public void Connect()
317 {
318
319 if (!m_enabled)
320 return;
321
322 // Delay until next WD cycle if this is too close to the last start attempt
323
324 while (_icc_ < ICCD_PERIOD)
325 return;
326
327 m_log.DebugFormat("[IRC-Connector-{0}]: Connection request for {1} on {2}:{3}", idn, m_nick, m_server, m_ircChannel);
328
329 lock (msyncConnect)
330 {
331
332 _icc_ = 0;
333
334 try
335 {
336 if (m_connected) return;
337
338 m_connected = true;
339 m_pending = true;
340 m_timeout = L_TIMEOUT;
341
342 m_tcp = new TcpClient(m_server, (int)m_port);
343 m_stream = m_tcp.GetStream();
344 m_reader = new StreamReader(m_stream);
345 m_writer = new StreamWriter(m_stream);
346
347 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port);
348
349 m_listener = new Thread(new ThreadStart(ListenerRun));
350 m_listener.Name = "IRCConnectorListenerThread";
351 m_listener.IsBackground = true;
352 m_listener.Start();
353 ThreadTracker.Add(m_listener);
354
355 // This is the message order recommended by RFC 2812
356 if (m_password != null)
357 m_writer.WriteLine(String.Format("PASS {0}", m_password));
358 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
359 m_writer.Flush();
360 m_writer.WriteLine(m_user);
361 m_writer.Flush();
362 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
363 m_writer.Flush();
364
365 m_log.InfoFormat("[IRC-Connector-{0}]: {1} has asked to join {2}", idn, m_nick, m_ircChannel);
366
367 }
368 catch (Exception e)
369 {
370 m_log.ErrorFormat("[IRC-Connector-{0}] cannot connect {1} to {2}:{3}: {4}",
371 idn, m_nick, m_server, m_port, e.Message);
372 m_connected = false;
373 m_pending = false;
374 }
375
376 }
377
378 return;
379
380 }
381
382 // Reconnect is used to force a re-cycle of the IRC connection. Should generally
383 // be a transparent event
384
385 public void Reconnect()
386 {
387 m_log.DebugFormat("[IRC-Connector-{0}]: Reconnect request for {1} on {2}:{3}", idn, m_nick, m_server, m_ircChannel);
388
389 // Don't do this if a Connect is in progress...
390
391 lock (msyncConnect)
392 {
393
394 if (m_connected)
395 {
396 m_log.InfoFormat("[IRC-Connector-{0}] Resetting connector", idn);
397
398 // Mark as disconnected. This will allow the listener thread
399 // to exit if still in-flight.
400
401
402 // The listener thread is not aborted - it *might* actually be
403 // the thread that is running the Reconnect! Instead just close
404 // the socket and it will disappear of its own accord, once this
405 // processing is completed.
406
407 try { m_writer.Close(); } catch (Exception) {}
408 try { m_reader.Close(); } catch (Exception) {}
409 try { m_tcp.Close(); } catch (Exception) {}
410
411 m_connected = false;
412 m_pending = false;
413
414 }
415
416 }
417
418 Connect();
419
420 }
421
422 #endregion
423
424 #region Outbound (to-IRC) message handlers
425
426 public void PrivMsg(string pattern, string from, string region, string msg)
427 {
428
429 m_log.DebugFormat("[IRC-Connector-{0}] PrivMsg to IRC from {1}: <{2}>", idn, from,
430 String.Format(pattern, m_ircChannel, from, region, msg));
431
432 // One message to the IRC server
433
434 try
435 {
436 m_writer.WriteLine(pattern, m_ircChannel, from, region, msg);
437 m_writer.Flush();
438 m_log.DebugFormat("[IRC-Connector-{0}]: PrivMsg from {1} in {2}: {3}", idn, from, region, msg);
439 }
440 catch (IOException)
441 {
442 m_log.ErrorFormat("[IRC-Connector-{0}]: PrivMsg I/O Error: disconnected from IRC server", idn);
443 Reconnect();
444 }
445 catch (Exception ex)
446 {
447 m_log.ErrorFormat("[IRC-Connector-{0}]: PrivMsg exception : {1}", idn, ex.Message);
448 m_log.Debug(ex);
449 }
450
451 }
452
453 public void Send(string msg)
454 {
455
456 m_log.DebugFormat("[IRC-Connector-{0}] Send to IRC : <{1}>", idn, msg);
457
458 try
459 {
460 m_writer.WriteLine(msg);
461 m_writer.Flush();
462 m_log.DebugFormat("[IRC-Connector-{0}] Sent command string: {1}", idn, msg);
463 }
464 catch (IOException)
465 {
466 m_log.ErrorFormat("[IRC-Connector-{0}] Disconnected from IRC server.(Send)", idn);
467 Reconnect();
468 }
469 catch (Exception ex)
470 {
471 m_log.ErrorFormat("[IRC-Connector-{0}] Send exception trap: {0}", idn, ex.Message);
472 m_log.Debug(ex);
473 }
474
475 }
476
477 #endregion
478
479 public void ListenerRun()
480 {
481 string inputLine;
482
483 try
484 {
485 while (m_enabled && m_connected)
486 {
487
488 if ((inputLine = m_reader.ReadLine()) == null)
489 throw new Exception("Listener input socket closed");
490
491 // m_log.Info("[IRCConnector]: " + inputLine);
492
493 if (inputLine.Contains("PRIVMSG"))
494 {
495
496 Dictionary<string, string> data = ExtractMsg(inputLine);
497
498 // Any chat ???
499 if (data != null)
500 {
501
502 OSChatMessage c = new OSChatMessage();
503 c.Message = data["msg"];
504 c.Type = ChatTypeEnum.Region;
505 c.Position = CenterOfRegion;
506 c.From = data["nick"];
507 c.Sender = null;
508 c.SenderUUID = UUID.Zero;
509
510 // Is message "\001ACTION foo bar\001"?
511 // Then change to: "/me foo bar"
512
513 if ((1 == c.Message[0]) && c.Message.Substring(1).StartsWith("ACTION"))
514 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9));
515
516 ChannelState.OSChat(this, c, false);
517
518 }
519
520 }
521 else
522 {
523 ProcessIRCCommand(inputLine);
524 }
525 }
526 }
527 catch (Exception /*e*/)
528 {
529 // m_log.ErrorFormat("[IRC-Connector-{0}]: ListenerRun exception trap: {1}", idn, e.Message);
530 // m_log.Debug(e);
531 }
532
533 // This is potentially circular, but harmless if so.
534 // The connection is marked as not connected the first time
535 // through reconnect.
536
537 if (m_enabled) Reconnect();
538
539 }
540
541 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)",
542 RegexOptions.Multiline);
543
544 private Dictionary<string, string> ExtractMsg(string input)
545 {
546 //examines IRC commands and extracts any private messages
547 // which will then be reboadcast in the Sim
548
549 // m_log.InfoFormat("[IRC-Connector-{0}]: ExtractMsg: {1}", idn, input);
550
551 Dictionary<string, string> result = null;
552 MatchCollection matches = RE.Matches(input);
553
554 // Get some direct matches $1 $4 is a
555 if ((matches.Count == 0) || (matches.Count != 1) || (matches[0].Groups.Count != 5))
556 {
557 // m_log.Info("[IRCConnector]: Number of matches: " + matches.Count);
558 // if (matches.Count > 0)
559 // {
560 // m_log.Info("[IRCConnector]: Number of groups: " + matches[0].Groups.Count);
561 // }
562 return null;
563 }
564
565 result = new Dictionary<string, string>();
566 result.Add("nick", matches[0].Groups[1].Value);
567 result.Add("user", matches[0].Groups[2].Value);
568 result.Add("channel", matches[0].Groups[3].Value);
569 result.Add("msg", matches[0].Groups[4].Value);
570
571 return result;
572 }
573
574 public void BroadcastSim(string sender, string format, params string[] args)
575 {
576 try
577 {
578 OSChatMessage c = new OSChatMessage();
579 c.From = sender;
580 c.Message = String.Format(format, args);
581 c.Type = ChatTypeEnum.Region; // ChatTypeEnum.Say;
582 c.Position = CenterOfRegion;
583 c.Sender = null;
584 c.SenderUUID = UUID.Zero;
585
586 ChannelState.OSChat(this, c, true);
587
588 }
589 catch (Exception ex) // IRC gate should not crash Sim
590 {
591 m_log.ErrorFormat("[IRC-Connector-{0}]: BroadcastSim Exception Trap: {1}\n{2}", idn, ex.Message, ex.StackTrace);
592 }
593 }
594
595 #region IRC Command Handlers
596
597 public void ProcessIRCCommand(string command)
598 {
599
600 string[] commArgs;
601 string c_server = m_server;
602
603 string pfx = String.Empty;
604 string cmd = String.Empty;
605 string parms = String.Empty;
606
607 // ":" indicates that a prefix is present
608 // There are NEVER more than 17 real
609 // fields. A parameter that starts with
610 // ":" indicates that the remainder of the
611 // line is a single parameter value.
612
613 commArgs = command.Split(CS_SPACE,2);
614
615 if (commArgs[0].StartsWith(":"))
616 {
617 pfx = commArgs[0].Substring(1);
618 commArgs = commArgs[1].Split(CS_SPACE,2);
619 }
620
621 cmd = commArgs[0];
622 parms = commArgs[1];
623
624 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd);
625
626 switch (cmd)
627 {
628
629 // Messages 001-004 are always sent
630 // following signon.
631
632 case "001" : // Welcome ...
633 case "002" : // Server information
634 case "003" : // Welcome ...
635 break;
636 case "004" : // Server information
637 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
638 commArgs = parms.Split(CS_SPACE);
639 c_server = commArgs[1];
640 m_server = c_server;
641 version = commArgs[2];
642 usermod = commArgs[3];
643 chanmod = commArgs[4];
644 break;
645 case "005" : // Server information
646 break;
647 case "042" :
648 case "250" :
649 case "251" :
650 case "252" :
651 case "254" :
652 case "255" :
653 case "265" :
654 case "266" :
655 case "332" : // Subject
656 case "333" : // Subject owner (?)
657 case "353" : // Name list
658 case "366" : // End-of-Name list marker
659 case "372" : // MOTD body
660 case "375" : // MOTD start
661 m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
662 break;
663 case "376" : // MOTD end
664 m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
665 motd = true;
666 break;
667 case "451" : // Not registered
668 break;
669 case "433" : // Nickname in use
670 // Gen a new name
671 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
672 m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick);
673 // Retry
674 m_writer.WriteLine(String.Format("NICK {0}", m_nick));
675 m_writer.Flush();
676 m_writer.WriteLine(m_user);
677 m_writer.Flush();
678 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
679 m_writer.Flush();
680 break;
681 case "479" : // Bad channel name, etc. This will never work, so disable the connection
682 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
683 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd);
684 m_enabled = false;
685 m_connected = false;
686 m_pending = false;
687 break;
688 case "NOTICE" :
689 m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
690 break;
691 case "ERROR" :
692 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
693 if (parms.Contains("reconnect too fast"))
694 ICCD_PERIOD++;
695 m_pending = false;
696 Reconnect();
697 break;
698 case "PING" :
699 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
700 m_writer.WriteLine(String.Format("PONG {0}", parms));
701 m_writer.Flush();
702 break;
703 case "PONG" :
704 break;
705 case "JOIN":
706 if (m_pending)
707 {
708 m_log.InfoFormat("[IRC-Connector-{0}] [{1}] Connected", idn, cmd);
709 m_pending = false;
710 }
711 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
712 eventIrcJoin(pfx, cmd, parms);
713 break;
714 case "PART":
715 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
716 eventIrcPart(pfx, cmd, parms);
717 break;
718 case "MODE":
719 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
720 eventIrcMode(pfx, cmd, parms);
721 break;
722 case "NICK":
723 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
724 eventIrcNickChange(pfx, cmd, parms);
725 break;
726 case "KICK":
727 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
728 eventIrcKick(pfx, cmd, parms);
729 break;
730 case "QUIT":
731 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
732 eventIrcQuit(pfx, cmd, parms);
733 break;
734 default :
735 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms);
736 break;
737 }
738
739 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd);
740
741 }
742
743 public void eventIrcJoin(string prefix, string command, string parms)
744 {
745 string[] args = parms.Split(CS_SPACE,2);
746 string IrcUser = prefix.Split('!')[0];
747 string IrcChannel = args[0];
748
749 if (IrcChannel.StartsWith(":"))
750 IrcChannel = IrcChannel.Substring(1);
751
752 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCJoin {1}:{2}", idn, m_server, m_ircChannel);
753 BroadcastSim(IrcUser, "/me joins {0}", IrcChannel);
754 }
755
756 public void eventIrcPart(string prefix, string command, string parms)
757 {
758 string[] args = parms.Split(CS_SPACE,2);
759 string IrcUser = prefix.Split('!')[0];
760 string IrcChannel = args[0];
761
762 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel);
763 BroadcastSim(IrcUser, "/me parts {0}", IrcChannel);
764 }
765
766 public void eventIrcMode(string prefix, string command, string parms)
767 {
768 string[] args = parms.Split(CS_SPACE,2);
769 string UserMode = args[1];
770
771 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel);
772 if (UserMode.Substring(0, 1) == ":")
773 {
774 UserMode = UserMode.Remove(0, 1);
775 }
776 }
777
778 public void eventIrcNickChange(string prefix, string command, string parms)
779 {
780 string[] args = parms.Split(CS_SPACE,2);
781 string UserOldNick = prefix.Split('!')[0];
782 string UserNewNick = args[0].Remove(0, 1);
783
784 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCNickChange {1}:{2}", idn, m_server, m_ircChannel);
785 BroadcastSim(UserOldNick, "/me is now known as {0}", UserNewNick);
786 }
787
788 public void eventIrcKick(string prefix, string command, string parms)
789 {
790 string[] args = parms.Split(CS_SPACE,3);
791 string UserKicker = prefix.Split('!')[0];
792 string IrcChannel = args[0];
793 string UserKicked = args[1];
794 string KickMessage = args[2];
795
796 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel);
797 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
798
799 if (UserKicked == m_nick)
800 {
801 BroadcastSim(m_nick, "Hey, that was me!!!");
802 }
803
804 }
805
806 public void eventIrcQuit(string prefix, string command, string parms)
807 {
808 string IrcUser = prefix.Split('!')[0];
809 string QuitMessage = parms;
810
811 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel);
812 BroadcastSim(IrcUser, "/me quits saying \"{0}\"", QuitMessage);
813 }
814
815 #endregion
816
817 #region Connector Watch Dog
818
819 // A single watch dog monitors extant connectors and makes sure that they
820 // are re-connected as necessary. If a connector IS connected, then it is
821 // pinged, but only if a PING period has elapsed.
822
823 protected static void WatchdogHandler(Object source, ElapsedEventArgs args)
824 {
825
826 // m_log.InfoFormat("[IRC-Watchdog] Status scan");
827
828 _pdk_ = (_pdk_+1)%PING_PERIOD; // cycle the ping trigger
829 _icc_++; // increment the inter-consecutive-connect-delay counter
830
831 foreach (IRCConnector connector in m_connectors)
832 {
833 if (connector.Enabled)
834 {
835 if (!connector.Connected)
836 {
837 try
838 {
839 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel);
840 connector.Connect();
841 }
842 catch (Exception e)
843 {
844 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
845 }
846 }
847 else
848 {
849
850 if (connector.m_pending)
851 {
852 if (connector.m_timeout == 0)
853 {
854 m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn);
855 connector.Reconnect();
856 }
857 else
858 connector.m_timeout--;
859 }
860
861 if (_pdk_ == 0)
862 {
863 try
864 {
865 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
866 connector.m_writer.Flush();
867 }
868 catch (Exception /*e*/)
869 {
870 // m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message);
871 // m_log.Debug(e);
872 connector.Reconnect();
873 }
874 }
875
876 }
877 }
878 }
879
880 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed");
881
882 }
883
884 #endregion
885
886 }
887}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
new file mode 100644
index 0000000..6733120
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
@@ -0,0 +1,424 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Text.RegularExpressions;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.Region.OptionalModules.Avatar.Chat
39{
40 // An instance of this class exists for every active region
41
42 internal class RegionState
43 {
44
45 private static readonly ILog m_log =
46 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(128, 128, 20);
49 private const int DEBUG_CHANNEL = 2147483647;
50
51 private static int _idk_ = 0;
52
53 // Runtime variables; these values are assigned when the
54 // IrcState is created and remain constant thereafter.
55
56 internal string Region = String.Empty;
57 internal string Host = String.Empty;
58 internal string LocX = String.Empty;
59 internal string LocY = String.Empty;
60 internal string MA1 = String.Empty;
61 internal string MA2 = String.Empty;
62 internal string IDK = String.Empty;
63
64 // System values - used only be the IRC classes themselves
65
66 internal ChannelState cs = null; // associated IRC configuration
67 internal Scene scene = null; // associated scene
68 internal IConfig config = null; // configuration file reference
69 internal bool enabled = true;
70
71 // This list is used to keep track of who is here, and by
72 // implication, who is not.
73
74 internal List<IClientAPI> clients = new List<IClientAPI>();
75
76 // Setup runtime variable values
77
78 public RegionState(Scene p_scene, IConfig p_config)
79 {
80
81 scene = p_scene;
82 config = p_config;
83
84 Region = scene.RegionInfo.RegionName;
85 Host = scene.RegionInfo.ExternalHostName;
86 LocX = Convert.ToString(scene.RegionInfo.RegionLocX);
87 LocY = Convert.ToString(scene.RegionInfo.RegionLocY);
88 MA1 = scene.RegionInfo.MasterAvatarFirstName;
89 MA2 = scene.RegionInfo.MasterAvatarLastName;
90 IDK = Convert.ToString(_idk_++);
91
92 // OpenChannel conditionally establishes a connection to the
93 // IRC server. The request will either succeed, or it will
94 // throw an exception.
95
96 ChannelState.OpenChannel(this, config);
97
98 // Connect channel to world events
99
100 scene.EventManager.OnChatFromWorld += OnSimChat;
101 scene.EventManager.OnChatFromClient += OnSimChat;
102 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
103 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
104
105 m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region);
106
107 }
108
109 // Auto cleanup when abandoned
110
111 ~RegionState()
112 {
113 if (cs != null)
114 cs.RemoveRegion(this);
115 }
116
117 // Called by PostInitialize after all regions have been created
118
119 public void Open()
120 {
121 cs.Open(this);
122 enabled = true;
123 }
124
125 // Called by IRCBridgeModule.Close immediately prior to unload
126 // of the module for this region. This happens when the region
127 // is being removed or the server is terminating. The IRC
128 // BridgeModule will remove the region from the region list
129 // when control returns.
130
131 public void Close()
132 {
133 enabled = false;
134 cs.Close(this);
135 }
136
137 // The agent has disconnected, cleanup associated resources
138
139 private void OnClientLoggedOut(IClientAPI client)
140 {
141 try
142 {
143 if (clients.Contains(client))
144 {
145 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
146 {
147 m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name);
148 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name));
149 }
150 client.OnLogout -= OnClientLoggedOut;
151 client.OnConnectionClosed -= OnClientLoggedOut;
152 clients.Remove(client);
153 }
154 }
155 catch (Exception ex)
156 {
157 m_log.ErrorFormat("[IRC-Region {0}]: ClientLoggedOut exception: {1}", Region, ex.Message);
158 m_log.Debug(ex);
159 }
160 }
161
162 // This event indicates that the agent has left the building. We should treat that the same
163 // as if the agent has logged out (we don't want cross-region noise - or do we?)
164
165 private void OnMakeChildAgent(ScenePresence presence)
166 {
167
168 IClientAPI client = presence.ControllingClient;
169
170 try
171 {
172 if (clients.Contains(client))
173 {
174 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
175 {
176 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
177 m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName);
178 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName));
179 }
180 client.OnLogout -= OnClientLoggedOut;
181 client.OnConnectionClosed -= OnClientLoggedOut;
182 clients.Remove(client);
183 }
184 }
185 catch (Exception ex)
186 {
187 m_log.ErrorFormat("[IRC-Region {0}]: MakeChildAgent exception: {1}", Region, ex.Message);
188 m_log.Debug(ex);
189 }
190
191 }
192
193 // An agent has entered the region (from another region). Add the client to the locally
194 // known clients list
195
196 private void OnMakeRootAgent(ScenePresence presence)
197 {
198
199 IClientAPI client = presence.ControllingClient;
200
201 try
202 {
203 if (!clients.Contains(client))
204 {
205 client.OnLogout += OnClientLoggedOut;
206 client.OnConnectionClosed += OnClientLoggedOut;
207 clients.Add(client);
208 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
209 {
210 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
211 m_log.DebugFormat("[IRC-Region {0}] {1} has arrived", Region, clientName);
212 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has arrived", clientName));
213 }
214 }
215 }
216 catch (Exception ex)
217 {
218 m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message);
219 m_log.Debug(ex);
220 }
221
222 }
223
224 // This handler detects chat events int he virtual world.
225
226 public void OnSimChat(Object sender, OSChatMessage msg)
227 {
228
229 // early return if this comes from the IRC forwarder
230
231 if (cs.irc.Equals(sender)) return;
232
233 // early return if nothing to forward
234
235 if (msg.Message.Length == 0) return;
236
237 // check for commands coming from avatars or in-world
238 // object (if commands are enabled)
239
240 if (cs.CommandsEnabled && msg.Channel == cs.CommandChannel)
241 {
242
243 m_log.DebugFormat("[IRC-Region {0}] command on channel {1}: {2}", Region, msg.Channel, msg.Message);
244
245 string[] messages = msg.Message.Split(' ');
246 string command = messages[0].ToLower();
247
248 try
249 {
250 switch (command)
251 {
252
253 // These commands potentially require a change in the
254 // underlying ChannelState.
255
256 case "server":
257 cs.Close(this);
258 cs = cs.UpdateServer(this, messages[1]);
259 cs.Open(this);
260 break;
261 case "port":
262 cs.Close(this);
263 cs = cs.UpdatePort(this, messages[1]);
264 cs.Open(this);
265 break;
266 case "channel":
267 cs.Close(this);
268 cs = cs.UpdateChannel(this, messages[1]);
269 cs.Open(this);
270 break;
271 case "nick":
272 cs.Close(this);
273 cs = cs.UpdateNickname(this, messages[1]);
274 cs.Open(this);
275 break;
276
277 // These may also (but are less likely) to require a
278 // change in ChannelState.
279
280 case "client-reporting":
281 cs = cs.UpdateClientReporting(this, messages[1]);
282 break;
283 case "in-channel":
284 cs = cs.UpdateRelayIn(this, messages[1]);
285 break;
286 case "out-channel":
287 cs = cs.UpdateRelayOut(this, messages[1]);
288 break;
289
290 // These are all taken to be temporary changes in state
291 // so the underlying connector remains intact. But note
292 // that with regions sharing a connector, there could
293 // be interference.
294
295 case "close":
296 enabled = false;
297 cs.Close(this);
298 break;
299
300 case "connect":
301 enabled = true;
302 cs.Open(this);
303 break;
304
305 case "reconnect":
306 enabled = true;
307 cs.Close(this);
308 cs.Open(this);
309 break;
310
311 // This one is harmless as far as we can judge from here.
312 // If it is not, then the complaints will eventually make
313 // that evident.
314
315 default:
316 m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}",
317 Region, msg.Message);
318 cs.irc.Send(msg.Message);
319 break;
320 }
321 }
322 catch (Exception ex)
323 {
324 m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}",
325 Region, ex.Message);
326 m_log.Debug(ex);
327 }
328
329 return;
330
331 }
332
333 // The command channel remains enabled, even if we have otherwise disabled the IRC
334 // interface.
335
336 if (!enabled)
337 return;
338
339 // drop messages unless they are on a valid in-world
340 // channel as configured in the ChannelState
341
342 if (!cs.ValidInWorldChannels.Contains(msg.Channel))
343 {
344 m_log.DebugFormat("[IRC-Region {0}] dropping message {1} on channel {2}", Region, msg, msg.Channel);
345 return;
346 }
347
348 ScenePresence avatar = null;
349 string fromName = msg.From;
350
351 if (msg.Sender != null)
352 {
353 avatar = scene.GetScenePresence(msg.Sender.AgentId);
354 if (avatar != null) fromName = avatar.Name;
355 }
356
357 if (!cs.irc.Connected)
358 {
359 m_log.WarnFormat("[IRC-Region {0}] IRCConnector not connected: dropping message from {1}", Region, fromName);
360 return;
361 }
362
363 m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message);
364
365 if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL))
366 {
367 string txt = msg.Message;
368 if (txt.StartsWith("/me "))
369 txt = String.Format("{0} {1}", fromName, msg.Message.Substring(4));
370
371 cs.irc.PrivMsg(cs.PrivateMessageFormat, fromName, Region, txt);
372 return;
373 }
374
375 if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword &&
376 msg.Channel == cs.RelayChannelOut)
377 {
378 Match m = cs.AccessPasswordRegex.Match(msg.Message);
379 if (null != m)
380 {
381 m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(),
382 m.Groups["message"].ToString());
383 cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(),
384 scene.RegionInfo.RegionName, m.Groups["message"].ToString());
385 }
386 }
387 }
388
389 // This method gives the region an opportunity to interfere with
390 // message delivery. For now we just enforce the enable/disable
391 // flag.
392
393 internal void OSChat(Object irc, OSChatMessage msg)
394 {
395 if (enabled)
396 {
397 // m_log.DebugFormat("[IRC-OSCHAT] Region {0} being sent message", region.Region);
398 msg.Scene = scene;
399 scene.EventManager.TriggerOnChatBroadcast(irc, msg);
400 }
401 }
402
403 // This supports any local message traffic that might be needed in
404 // support of command processing. At present there is none.
405
406 internal void LocalChat(string msg)
407 {
408 if (enabled)
409 {
410 OSChatMessage osm = new OSChatMessage();
411 osm.From = "IRC Agent";
412 osm.Message = msg;
413 osm.Type = ChatTypeEnum.Region;
414 osm.Position = CenterOfRegion;
415 osm.Sender = null;
416 osm.SenderUUID = OpenMetaverse.UUID.Zero; // Hmph! Still?
417 osm.Channel = 0;
418 OSChat(this, osm);
419 }
420 }
421
422 }
423
424}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
new file mode 100644
index 0000000..bb46b11
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
@@ -0,0 +1,604 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Net;
33using System.Net.Sockets;
34using System.Reflection;
35using System.Text;
36using System.Text.RegularExpressions;
37using System.Threading;
38using log4net;
39using Nini.Config;
40using Nwc.XmlRpc;
41using OpenMetaverse;
42using OpenSim.Framework;
43using OpenSim.Framework.Servers;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Region.CoreModules.Avatar.Chat;
47
48namespace OpenSim.Region.OptionalModules.Avatar.Concierge
49{
50 public class ConciergeModule : ChatModule, IRegionModule
51 {
52 private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private const int DEBUG_CHANNEL = 2147483647;
55
56 private List<IScene> _scenes = new List<IScene>();
57 private List<IScene> _conciergedScenes = new List<IScene>();
58 private Dictionary<IScene, List<UUID>> _sceneAttendees =
59 new Dictionary<IScene, List<UUID>>();
60 private Dictionary<UUID, string> _attendeeNames =
61 new Dictionary<UUID, string>();
62
63 private bool _replacingChatModule = false;
64
65 private IConfig _config;
66
67 private string _whoami = "conferencier";
68 private Regex _regions = null;
69 private string _welcomes = null;
70 private int _conciergeChannel = 42;
71 private string _announceEntering = "{0} enters {1} (now {2} visitors in this region)";
72 private string _announceLeaving = "{0} leaves {1} (back to {2} visitors in this region)";
73 private string _xmlRpcPassword = String.Empty;
74 private string _brokerURI = String.Empty;
75
76 internal object _syncy = new object();
77
78 #region IRegionModule Members
79 public override void Initialise(Scene scene, IConfigSource config)
80 {
81 try
82 {
83 if ((_config = config.Configs["Concierge"]) == null)
84 {
85 //_log.InfoFormat("[Concierge]: no configuration section [Concierge] in OpenSim.ini: module not configured");
86 return;
87 }
88
89 if (!_config.GetBoolean("enabled", false))
90 {
91 //_log.InfoFormat("[Concierge]: module disabled by OpenSim.ini configuration");
92 return;
93 }
94 }
95 catch (Exception)
96 {
97 _log.Info("[Concierge]: module not configured");
98 return;
99 }
100
101 // check whether ChatModule has been disabled: if yes,
102 // then we'll "stand in"
103 try
104 {
105 if (config.Configs["Chat"] == null)
106 {
107 _replacingChatModule = false;
108 }
109 else
110 {
111 _replacingChatModule = !config.Configs["Chat"].GetBoolean("enabled", true);
112 }
113 }
114 catch (Exception)
115 {
116 _replacingChatModule = false;
117 }
118 _log.InfoFormat("[Concierge] {0} ChatModule", _replacingChatModule ? "replacing" : "not replacing");
119
120
121 // take note of concierge channel and of identity
122 _conciergeChannel = config.Configs["Concierge"].GetInt("concierge_channel", _conciergeChannel);
123 _whoami = _config.GetString("whoami", "conferencier");
124 _welcomes = _config.GetString("welcomes", _welcomes);
125 _announceEntering = _config.GetString("announce_entering", _announceEntering);
126 _announceLeaving = _config.GetString("announce_leaving", _announceLeaving);
127 _xmlRpcPassword = _config.GetString("password", _xmlRpcPassword);
128 _brokerURI = _config.GetString("broker", _brokerURI);
129
130 _log.InfoFormat("[Concierge] reporting as \"{0}\" to our users", _whoami);
131
132 // calculate regions Regex
133 if (_regions == null)
134 {
135 string regions = _config.GetString("regions", String.Empty);
136 if (!String.IsNullOrEmpty(regions))
137 {
138 _regions = new Regex(@regions, RegexOptions.Compiled | RegexOptions.IgnoreCase);
139 }
140 }
141
142 scene.CommsManager.HttpServer.AddXmlRPCHandler("concierge_update_welcome", XmlRpcUpdateWelcomeMethod, false);
143
144 lock (_syncy)
145 {
146 if (!_scenes.Contains(scene))
147 {
148 _scenes.Add(scene);
149
150 if (_regions == null || _regions.IsMatch(scene.RegionInfo.RegionName))
151 _conciergedScenes.Add(scene);
152
153 // subscribe to NewClient events
154 scene.EventManager.OnNewClient += OnNewClient;
155
156 // subscribe to *Chat events
157 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
158 if (!_replacingChatModule)
159 scene.EventManager.OnChatFromClient += OnChatFromClient;
160 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
161
162 // subscribe to agent change events
163 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
164 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
165 }
166 }
167 _log.InfoFormat("[Concierge]: initialized for {0}", scene.RegionInfo.RegionName);
168 }
169
170 public override void PostInitialise()
171 {
172 }
173
174 public override void Close()
175 {
176 }
177
178 public override string Name
179 {
180 get { return "ConciergeModule"; }
181 }
182
183 public override bool IsSharedModule
184 {
185 get { return true; }
186 }
187
188 #endregion
189
190 #region ISimChat Members
191 public override void OnChatBroadcast(Object sender, OSChatMessage c)
192 {
193 if (_replacingChatModule)
194 {
195 // distribute chat message to each and every avatar in
196 // the region
197 base.OnChatBroadcast(sender, c);
198 }
199
200 // TODO: capture logic
201 return;
202 }
203
204 public override void OnChatFromClient(Object sender, OSChatMessage c)
205 {
206 if (_replacingChatModule)
207 {
208 // replacing ChatModule: need to redistribute
209 // ChatFromClient to interested subscribers
210 c = FixPositionOfChatMessage(c);
211
212 Scene scene = (Scene)c.Scene;
213 scene.EventManager.TriggerOnChatFromClient(sender, c);
214
215 if (_conciergedScenes.Contains(c.Scene))
216 {
217 // when we are replacing ChatModule, we treat
218 // OnChatFromClient like OnChatBroadcast for
219 // concierged regions, effectively extending the
220 // range of chat to cover the whole
221 // region. however, we don't do this for whisper
222 // (got to have some privacy)
223 if (c.Type != ChatTypeEnum.Whisper)
224 {
225 base.OnChatBroadcast(sender, c);
226 return;
227 }
228 }
229
230 // redistribution will be done by base class
231 base.OnChatFromClient(sender, c);
232 }
233
234 // TODO: capture chat
235 return;
236 }
237
238 public override void OnChatFromWorld(Object sender, OSChatMessage c)
239 {
240 if (_replacingChatModule)
241 {
242 if (_conciergedScenes.Contains(c.Scene))
243 {
244 // when we are replacing ChatModule, we treat
245 // OnChatFromClient like OnChatBroadcast for
246 // concierged regions, effectively extending the
247 // range of chat to cover the whole
248 // region. however, we don't do this for whisper
249 // (got to have some privacy)
250 if (c.Type != ChatTypeEnum.Whisper)
251 {
252 base.OnChatBroadcast(sender, c);
253 return;
254 }
255 }
256
257 base.OnChatFromWorld(sender, c);
258 }
259 return;
260 }
261 #endregion
262
263
264 public override void OnNewClient(IClientAPI client)
265 {
266 client.OnLogout += OnClientLoggedOut;
267
268 if (_replacingChatModule)
269 client.OnChatFromClient += OnChatFromClient;
270 }
271
272
273
274 public void OnClientLoggedOut(IClientAPI client)
275 {
276 client.OnLogout -= OnClientLoggedOut;
277 client.OnConnectionClosed -= OnClientLoggedOut;
278
279 if (_conciergedScenes.Contains(client.Scene))
280 {
281 _log.DebugFormat("[Concierge]: {0} logs off from {1}", client.Name, client.Scene.RegionInfo.RegionName);
282 RemoveFromAttendeeList(client.AgentId, client.Name, client.Scene);
283 AnnounceToAgentsRegion(client.Scene, String.Format(_announceLeaving, client.Name, client.Scene.RegionInfo.RegionName,
284 _sceneAttendees[client.Scene].Count));
285 UpdateBroker(client.Scene);
286 }
287 }
288
289
290 public void OnMakeRootAgent(ScenePresence agent)
291 {
292 if (_conciergedScenes.Contains(agent.Scene))
293 {
294 _log.DebugFormat("[Concierge]: {0} enters {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
295 AddToAttendeeList(agent.UUID, agent.Name, agent.Scene);
296 WelcomeAvatar(agent, agent.Scene);
297 AnnounceToAgentsRegion(agent.Scene, String.Format(_announceEntering, agent.Name, agent.Scene.RegionInfo.RegionName,
298 _sceneAttendees[agent.Scene].Count));
299 UpdateBroker(agent.Scene);
300 }
301 }
302
303
304 public void OnMakeChildAgent(ScenePresence agent)
305 {
306 if (_conciergedScenes.Contains(agent.Scene))
307 {
308 _log.DebugFormat("[Concierge]: {0} leaves {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
309 RemoveFromAttendeeList(agent.UUID, agent.Name, agent.Scene);
310 AnnounceToAgentsRegion(agent.Scene, String.Format(_announceLeaving, agent.Name, agent.Scene.RegionInfo.RegionName,
311 _sceneAttendees[agent.Scene].Count));
312 UpdateBroker(agent.Scene);
313 }
314 }
315
316 protected void AddToAttendeeList(UUID agentID, string name, Scene scene)
317 {
318 lock (_sceneAttendees)
319 {
320 if (!_sceneAttendees.ContainsKey(scene))
321 _sceneAttendees[scene] = new List<UUID>();
322
323 List<UUID> attendees = _sceneAttendees[scene];
324 if (!attendees.Contains(agentID))
325 {
326 attendees.Add(agentID);
327 _attendeeNames[agentID] = name;
328 }
329 }
330 }
331
332 protected void RemoveFromAttendeeList(UUID agentID, String name, IScene scene)
333 {
334 lock (_sceneAttendees)
335 {
336 if (!_sceneAttendees.ContainsKey(scene))
337 {
338 _log.WarnFormat("[Concierge]: attendee list missing for region {0}", scene.RegionInfo.RegionName);
339 return;
340 }
341
342 List<UUID> attendees = _sceneAttendees[scene];
343 if (!attendees.Contains(agentID))
344 {
345 _log.WarnFormat("[Concierge]: avatar {0} must have sneaked in to region {1} earlier",
346 name, scene.RegionInfo.RegionName);
347 return;
348 }
349
350 attendees.Remove(agentID);
351 _attendeeNames.Remove(agentID);
352 }
353 }
354
355 protected void UpdateBroker(IScene scene)
356 {
357 if (String.IsNullOrEmpty(_brokerURI))
358 return;
359
360 string uri = String.Format(_brokerURI, scene.RegionInfo.RegionName, scene.RegionInfo.RegionID);
361
362 // get attendee list for the scene
363 List<UUID> attendees;
364 lock (_sceneAttendees)
365 {
366 if (!_sceneAttendees.ContainsKey(scene))
367 {
368 _log.DebugFormat("[Concierge]: attendee list missing for region {0}", scene.RegionInfo.RegionName);
369 return;
370 }
371
372 attendees = _sceneAttendees[scene];
373 }
374
375 // create XML sniplet
376 StringBuilder list = new StringBuilder();
377 if (0 == attendees.Count)
378 {
379 list.Append(String.Format("<avatars count=\"0\" region_name=\"{0}\" region_uuid=\"{1}\" timestamp=\"{2}\" />",
380 scene.RegionInfo.RegionName, scene.RegionInfo.RegionID,
381 DateTime.UtcNow.ToString("s")));
382 }
383 else
384 {
385 list.Append(String.Format("<avatars count=\"{0}\" region_name=\"{1}\" region_uuid=\"{2}\" timestamp=\"{3}\">\n",
386 attendees.Count, scene.RegionInfo.RegionName,
387 scene.RegionInfo.RegionID,
388 DateTime.UtcNow.ToString("s")));
389 foreach (UUID uuid in attendees)
390 {
391 string name = _attendeeNames[uuid];
392 list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", name, uuid));
393 }
394 list.Append("</avatars>");
395 }
396 string payload = list.ToString();
397
398 // post via REST to broker
399 HttpWebRequest updatePost = WebRequest.Create(uri) as HttpWebRequest;
400 updatePost.Method = "POST";
401 updatePost.ContentType = "text/xml";
402 updatePost.ContentLength = payload.Length;
403 updatePost.UserAgent = "OpenSim.Concierge";
404
405 try
406 {
407 StreamWriter payloadStream = new StreamWriter(updatePost.GetRequestStream());
408 payloadStream.Write(payload);
409 payloadStream.Close();
410
411 updatePost.BeginGetResponse(UpdateBrokerDone, updatePost);
412 _log.DebugFormat("[Concierge] async broker POST to {0} started", uri);
413 }
414 catch (WebException we)
415 {
416 _log.ErrorFormat("[Concierge] async broker POST to {0} failed: {1}", uri, we.Status);
417 }
418 }
419
420 private void UpdateBrokerDone(IAsyncResult result)
421 {
422 HttpWebRequest updatePost = null;
423 try
424 {
425 updatePost = result.AsyncState as HttpWebRequest;
426 using (HttpWebResponse response = updatePost.EndGetResponse(result) as HttpWebResponse)
427 {
428 _log.DebugFormat("[Concierge] broker update: status {0}", response.StatusCode);
429 }
430 }
431 catch (WebException we)
432 {
433 string uri = updatePost.RequestUri.OriginalString;
434 _log.ErrorFormat("[Concierge] broker update to {0} failed with status {1}", uri, we.Status);
435 if (null != we.Response)
436 {
437 using (HttpWebResponse resp = we.Response as HttpWebResponse)
438 {
439 _log.ErrorFormat("[Concierge] response from {0} status code: {1}", uri, resp.StatusCode);
440 _log.ErrorFormat("[Concierge] response from {0} status desc: {1}", uri, resp.StatusDescription);
441 _log.ErrorFormat("[Concierge] response from {0} server: {1}", uri, resp.Server);
442
443 if (resp.ContentLength > 0)
444 {
445 StreamReader content = new StreamReader(resp.GetResponseStream());
446 _log.ErrorFormat("[Concierge] response from {0} content: {1}", uri, content.ReadToEnd());
447 content.Close();
448 }
449 }
450 }
451 }
452 }
453
454 protected void WelcomeAvatar(ScenePresence agent, Scene scene)
455 {
456 // welcome mechanics: check whether we have a welcomes
457 // directory set and wether there is a region specific
458 // welcome file there: if yes, send it to the agent
459 if (!String.IsNullOrEmpty(_welcomes))
460 {
461 string[] welcomes = new string[] {
462 Path.Combine(_welcomes, agent.Scene.RegionInfo.RegionName),
463 Path.Combine(_welcomes, "DEFAULT")};
464 foreach (string welcome in welcomes)
465 {
466 if (File.Exists(welcome))
467 {
468 try
469 {
470 string[] welcomeLines = File.ReadAllLines(welcome);
471 foreach (string l in welcomeLines)
472 {
473 AnnounceToAgent(agent, String.Format(l, agent.Name, scene.RegionInfo.RegionName, _whoami));
474 }
475 }
476 catch (IOException ioe)
477 {
478 _log.ErrorFormat("[Concierge]: run into trouble reading welcome file {0} for region {1} for avatar {2}: {3}",
479 welcome, scene.RegionInfo.RegionName, agent.Name, ioe);
480 }
481 catch (FormatException fe)
482 {
483 _log.ErrorFormat("[Concierge]: welcome file {0} is malformed: {1}", welcome, fe);
484 }
485 }
486 return;
487 }
488 _log.DebugFormat("[Concierge]: no welcome message for region {0}", scene.RegionInfo.RegionName);
489 }
490 }
491
492 static private Vector3 PosOfGod = new Vector3(128, 128, 9999);
493
494 // protected void AnnounceToAgentsRegion(Scene scene, string msg)
495 // {
496 // ScenePresence agent = null;
497 // if ((client.Scene is Scene) && (client.Scene as Scene).TryGetAvatar(client.AgentId, out agent))
498 // AnnounceToAgentsRegion(agent, msg);
499 // else
500 // _log.DebugFormat("[Concierge]: could not find an agent for client {0}", client.Name);
501 // }
502
503 protected void AnnounceToAgentsRegion(IScene scene, string msg)
504 {
505 OSChatMessage c = new OSChatMessage();
506 c.Message = msg;
507 c.Type = ChatTypeEnum.Say;
508 c.Channel = 0;
509 c.Position = PosOfGod;
510 c.From = _whoami;
511 c.Sender = null;
512 c.SenderUUID = UUID.Zero;
513 c.Scene = scene;
514
515 if (scene is Scene)
516 (scene as Scene).EventManager.TriggerOnChatBroadcast(this, c);
517 }
518
519 protected void AnnounceToAgent(ScenePresence agent, string msg)
520 {
521 OSChatMessage c = new OSChatMessage();
522 c.Message = msg;
523 c.Type = ChatTypeEnum.Say;
524 c.Channel = 0;
525 c.Position = PosOfGod;
526 c.From = _whoami;
527 c.Sender = null;
528 c.SenderUUID = UUID.Zero;
529 c.Scene = agent.Scene;
530
531 agent.ControllingClient.SendChatMessage(msg, (byte) ChatTypeEnum.Say, PosOfGod, _whoami, UUID.Zero,
532 (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
533 }
534
535 private static void checkStringParameters(XmlRpcRequest request, string[] param)
536 {
537 Hashtable requestData = (Hashtable) request.Params[0];
538 foreach (string p in param)
539 {
540 if (!requestData.Contains(p))
541 throw new Exception(String.Format("missing string parameter {0}", p));
542 if (String.IsNullOrEmpty((string)requestData[p]))
543 throw new Exception(String.Format("parameter {0} is empty", p));
544 }
545 }
546
547 public XmlRpcResponse XmlRpcUpdateWelcomeMethod(XmlRpcRequest request)
548 {
549 _log.Info("[Concierge]: processing UpdateWelcome request");
550 XmlRpcResponse response = new XmlRpcResponse();
551 Hashtable responseData = new Hashtable();
552
553 try
554 {
555 Hashtable requestData = (Hashtable)request.Params[0];
556 checkStringParameters(request, new string[] { "password", "region", "welcome" });
557
558 // check password
559 if (!String.IsNullOrEmpty(_xmlRpcPassword) &&
560 (string)requestData["password"] != _xmlRpcPassword) throw new Exception("wrong password");
561
562 if (String.IsNullOrEmpty(_welcomes))
563 throw new Exception("welcome templates are not enabled, ask your OpenSim operator to set the \"welcomes\" option in the [Concierge] section of OpenSim.ini");
564
565 string msg = (string)requestData["welcome"];
566 if (String.IsNullOrEmpty(msg))
567 throw new Exception("empty parameter \"welcome\"");
568
569 string regionName = (string)requestData["region"];
570 IScene scene = _scenes.Find(delegate(IScene s) { return s.RegionInfo.RegionName == regionName; });
571 if (scene == null)
572 throw new Exception(String.Format("unknown region \"{0}\"", regionName));
573
574 if (!_conciergedScenes.Contains(scene))
575 throw new Exception(String.Format("region \"{0}\" is not a concierged region.", regionName));
576
577 string welcome = Path.Combine(_welcomes, regionName);
578 if (File.Exists(welcome))
579 {
580 _log.InfoFormat("[Concierge]: UpdateWelcome: updating existing template \"{0}\"", welcome);
581 string welcomeBackup = String.Format("{0}~", welcome);
582 if (File.Exists(welcomeBackup))
583 File.Delete(welcomeBackup);
584 File.Move(welcome, welcomeBackup);
585 }
586 File.WriteAllText(welcome, msg);
587
588 responseData["success"] = "true";
589 response.Value = responseData;
590 }
591 catch (Exception e)
592 {
593 _log.InfoFormat("[Concierge]: UpdateWelcome failed: {0}", e.Message);
594
595 responseData["success"] = "false";
596 responseData["error"] = e.Message;
597
598 response.Value = responseData;
599 }
600 _log.Debug("[Concierge]: done processing UpdateWelcome request");
601 return response;
602 }
603 }
604}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeServer.py b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeServer.py
new file mode 100755
index 0000000..1c088fb
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeServer.py
@@ -0,0 +1,130 @@
1#!/usr/bin/env python
2# -*- encoding: utf-8 -*-
3#
4# Copyright (c) Contributors, http://opensimulator.org/
5# See CONTRIBUTORS.TXT for a full list of copyright holders.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions are met:
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above copyright
12# notice, this list of conditions and the following disclaimer in the
13# documentation and/or other materials provided with the distribution.
14# * Neither the name of the OpenSim Project nor the
15# names of its contributors may be used to endorse or promote products
16# derived from this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
19# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
22# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29
30import logging
31import BaseHTTPServer
32import optparse
33import xml.etree.ElementTree as ET
34import xml.parsers.expat
35
36
37# enable debug level logging
38logging.basicConfig(level = logging.DEBUG,
39 format='%(asctime)s %(levelname)s %(message)s')
40
41options = None
42
43# subclassed HTTPRequestHandler
44class ConciergeHandler(BaseHTTPServer.BaseHTTPRequestHandler):
45 def logRequest(self):
46 logging.info('[ConciergeHandler] %(command)s request: %(host)s:%(port)d --- %(path)s',
47 dict(command = self.command,
48 host = self.client_address[0],
49 port = self.client_address[1],
50 path = self.path))
51
52 def logResponse(self, status):
53 logging.info('[ConciergeHandler] %(command)s returned %(status)d',
54 dict(command = self.command,
55 status = status))
56
57
58 def do_HEAD(self):
59 self.logRequest()
60
61 self.send_response(200)
62 self.send_header('Content-type', 'text/html')
63 self.end_headers()
64
65 self.logResponse(200)
66
67 def dumpXml(self, xml):
68 logging.debug('[ConciergeHandler] %s', xml.tag)
69 for attr in xml.attrib:
70 logging.debug('[ConciergeHandler] %s [%s] %s', xml.tag, attr, xml.attrib[attr])
71 for kid in xml.getchildren():
72 self.dumpXml(kid)
73
74 def do_POST(self):
75 self.logRequest()
76 hdrs = {}
77 for hdr in self.headers.headers:
78 logging.debug('[ConciergeHandler] POST: header: %s', hdr.rstrip())
79
80 length = int(self.headers.getheader('Content-Length'))
81 content = self.rfile.read(length)
82 self.rfile.close()
83
84 logging.debug('[ConciergeHandler] POST: content: %s', content)
85 try:
86 postXml = ET.fromstring(content)
87 self.dumpXml(postXml)
88 except xml.parsers.expat.ExpatError, xmlError:
89 logging.error('[ConciergeHandler] POST illformed:%s', xmlError)
90 self.send_response(500)
91 return
92
93 if not options.fail:
94 self.send_response(200)
95 self.send_header('Content-Type', 'text/html')
96 self.send_header('Content-Length', len('<success/>'))
97 self.end_headers()
98 self.logResponse(200)
99 self.wfile.write('<success/>')
100 self.wfile.close()
101 else:
102 self.send_response(500)
103 self.send_header('Content-Type', 'text/html')
104 self.send_header('Content-Length', len('<error>gotcha!</error>'))
105 self.end_headers()
106 self.wfile.write('<error>gotcha!</error>')
107 self.wfile.close()
108
109 self.logResponse(500)
110
111 def log_request(code, size):
112 pass
113
114if __name__ == '__main__':
115
116 logging.info('[ConciergeServer] Concierge Broker Test Server starting')
117
118 parser = optparse.OptionParser()
119 parser.add_option('-p', '--port', dest = 'port', help = 'port to listen on', metavar = 'PORT')
120 parser.add_option('-f', '--fail', dest = 'fail', action = 'store_true', help = 'always fail POST requests')
121
122 (options, args) = parser.parse_args()
123
124 httpServer = BaseHTTPServer.HTTPServer(('', 8080), ConciergeHandler)
125 try:
126 httpServer.serve_forever()
127 except KeyboardInterrupt:
128 logging.info('[ConciergeServer] terminating')
129
130 httpServer.server_close()
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs
new file mode 100644
index 0000000..c827214
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/AsterixVoice/AsteriskVoiceModule.cs
@@ -0,0 +1,292 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Reflection;
31using OpenMetaverse;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using OpenSim.Framework;
36using OpenSim.Framework.Communications.Cache;
37using OpenSim.Framework.Communications.Capabilities;
38using OpenSim.Framework.Servers;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using Caps=OpenSim.Framework.Communications.Capabilities.Caps;
42
43namespace OpenSim.Region.OptionalModules.Avatar.Voice.AsterixVoice
44{
45 public class AsteriskVoiceModule : IRegionModule
46 {
47 private static readonly ILog m_log =
48 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 private static readonly string m_parcelVoiceInfoRequestPath = "0007/";
51 private static readonly string m_provisionVoiceAccountRequestPath = "0008/";
52
53 private string m_asterisk;
54 private string m_asterisk_password;
55 private string m_asterisk_salt;
56 private int m_asterisk_timeout;
57 private string m_confDomain;
58 private IConfig m_config;
59 private Scene m_scene;
60 private string m_sipDomain;
61
62 #region IRegionModule Members
63
64 public void Initialise(Scene scene, IConfigSource config)
65 {
66 m_scene = scene;
67 m_config = config.Configs["AsteriskVoice"];
68
69 if (null == m_config)
70 {
71 m_log.Info("[ASTERISKVOICE] no config found, plugin disabled");
72 return;
73 }
74
75 if (!m_config.GetBoolean("enabled", false))
76 {
77 m_log.Info("[ASTERISKVOICE] plugin disabled by configuration");
78 return;
79 }
80 m_log.Info("[ASTERISKVOICE] plugin enabled");
81
82 try
83 {
84 m_sipDomain = m_config.GetString("sip_domain", String.Empty);
85 m_log.InfoFormat("[ASTERISKVOICE] using SIP domain {0}", m_sipDomain);
86
87 m_confDomain = m_config.GetString("conf_domain", String.Empty);
88 m_log.InfoFormat("[ASTERISKVOICE] using conf domain {0}", m_confDomain);
89
90 m_asterisk = m_config.GetString("asterisk_frontend", String.Empty);
91 m_asterisk_password = m_config.GetString("asterisk_password", String.Empty);
92 m_asterisk_timeout = m_config.GetInt("asterisk_timeout", 3000);
93 m_asterisk_salt = m_config.GetString("asterisk_salt", "Wuffwuff");
94 if (String.IsNullOrEmpty(m_asterisk)) throw new Exception("missing asterisk_frontend config parameter");
95 if (String.IsNullOrEmpty(m_asterisk_password)) throw new Exception("missing asterisk_password config parameter");
96 m_log.InfoFormat("[ASTERISKVOICE] using asterisk front end {0}", m_asterisk);
97
98 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
99 }
100 catch (Exception e)
101 {
102 m_log.ErrorFormat("[ASTERISKVOICE] plugin initialization failed: {0}", e.Message);
103 m_log.DebugFormat("[ASTERISKVOICE] plugin initialization failed: {0}", e.ToString());
104 return;
105 }
106 }
107
108 public void PostInitialise()
109 {
110 }
111
112 public void Close()
113 {
114 }
115
116 public string Name
117 {
118 get { return "AsteriskVoiceModule"; }
119 }
120
121 public bool IsSharedModule
122 {
123 get { return false; }
124 }
125
126 #endregion
127
128 public void OnRegisterCaps(UUID agentID, Caps caps)
129 {
130 m_log.DebugFormat("[ASTERISKVOICE] OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
131 string capsBase = "/CAPS/" + caps.CapsObjectPath;
132 caps.RegisterHandler("ParcelVoiceInfoRequest",
133 new RestStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath,
134 delegate(string request, string path, string param,
135 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
136 {
137 return ParcelVoiceInfoRequest(request, path, param,
138 agentID, caps);
139 }));
140 caps.RegisterHandler("ProvisionVoiceAccountRequest",
141 new RestStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath,
142 delegate(string request, string path, string param,
143 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
144 {
145 return ProvisionVoiceAccountRequest(request, path, param,
146 agentID, caps);
147 }));
148 }
149
150 /// <summary>
151 /// Callback for a client request for ParcelVoiceInfo
152 /// </summary>
153 /// <param name="request"></param>
154 /// <param name="path"></param>
155 /// <param name="param"></param>
156 /// <param name="agentID"></param>
157 /// <param name="caps"></param>
158 /// <returns></returns>
159 public string ParcelVoiceInfoRequest(string request, string path, string param,
160 UUID agentID, Caps caps)
161 {
162 // we need to do:
163 // - send channel_uri: as "sip:regionID@m_sipDomain"
164 try
165 {
166 m_log.DebugFormat("[ASTERISKVOICE][PARCELVOICE]: request: {0}, path: {1}, param: {2}",
167 request, path, param);
168
169
170 // setup response to client
171 Hashtable creds = new Hashtable();
172 creds["channel_uri"] = String.Format("sip:{0}@{1}",
173 m_scene.RegionInfo.RegionID, m_sipDomain);
174
175 string regionName = m_scene.RegionInfo.RegionName;
176 ScenePresence avatar = m_scene.GetScenePresence(agentID);
177 if (null == m_scene.LandChannel) throw new Exception("land data not yet available");
178 LandData land = m_scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
179
180 LLSDParcelVoiceInfoResponse parcelVoiceInfo =
181 new LLSDParcelVoiceInfoResponse(regionName, land.LocalID, creds);
182
183 string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo);
184
185
186 // update region on asterisk-opensim frontend
187 Hashtable requestData = new Hashtable();
188 requestData["admin_password"] = m_asterisk_password;
189 requestData["region"] = m_scene.RegionInfo.RegionID.ToString();
190 if (!String.IsNullOrEmpty(m_confDomain))
191 {
192 requestData["region"] += String.Format("@{0}", m_confDomain);
193 }
194
195 ArrayList SendParams = new ArrayList();
196 SendParams.Add(requestData);
197 XmlRpcRequest updateAccountRequest = new XmlRpcRequest("region_update", SendParams);
198 XmlRpcResponse updateAccountResponse = updateAccountRequest.Send(m_asterisk, m_asterisk_timeout);
199 Hashtable responseData = (Hashtable) updateAccountResponse.Value;
200
201 if (!responseData.ContainsKey("success")) throw new Exception("region_update call failed");
202
203 bool success = Convert.ToBoolean((string) responseData["success"]);
204 if (!success) throw new Exception("region_update failed");
205
206
207 m_log.DebugFormat("[ASTERISKVOICE][PARCELVOICE]: {0}", r);
208 return r;
209 }
210 catch (Exception e)
211 {
212 m_log.ErrorFormat("[ASTERISKVOICE][CAPS][PARCELVOICE]: {0}, retry later", e.Message);
213 m_log.DebugFormat("[ASTERISKVOICE][CAPS][PARCELVOICE]: {0} failed", e.ToString());
214
215 return "<llsd>undef</llsd>";
216 }
217 }
218
219 /// <summary>
220 /// Callback for a client request for Voice Account Details
221 /// </summary>
222 /// <param name="request"></param>
223 /// <param name="path"></param>
224 /// <param name="param"></param>
225 /// <param name="agentID"></param>
226 /// <param name="caps"></param>
227 /// <returns></returns>
228 public string ProvisionVoiceAccountRequest(string request, string path, string param,
229 UUID agentID, Caps caps)
230 {
231 // we need to
232 // - get user data from UserProfileCacheService
233 // - generate nonce for user voice account password
234 // - issue XmlRpc request to asterisk opensim front end:
235 // + user: base 64 encoded user name (otherwise SL
236 // client is unhappy)
237 // + password: nonce
238 // - the XmlRpc call to asteris-opensim was successful:
239 // send account details back to client
240 try
241 {
242 m_log.DebugFormat("[ASTERISKVOICE][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}",
243 request, path, param);
244
245 // get user data & prepare voice account response
246 string voiceUser = "x" + Convert.ToBase64String(agentID.GetBytes());
247 voiceUser = voiceUser.Replace('+', '-').Replace('/', '_');
248
249 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID);
250 if (null == userInfo) throw new Exception("cannot get user details");
251
252 // we generate a nonce everytime
253 string voicePassword = "$1$" + Util.Md5Hash(DateTime.UtcNow.ToLongTimeString() + m_asterisk_salt);
254 LLSDVoiceAccountResponse voiceAccountResponse =
255 new LLSDVoiceAccountResponse(voiceUser, voicePassword);
256 string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse);
257 m_log.DebugFormat("[CAPS][PROVISIONVOICE]: {0}", r);
258
259
260 // update user account on asterisk frontend
261 Hashtable requestData = new Hashtable();
262 requestData["admin_password"] = m_asterisk_password;
263 requestData["username"] = voiceUser;
264 if (!String.IsNullOrEmpty(m_sipDomain))
265 {
266 requestData["username"] += String.Format("@{0}", m_sipDomain);
267 }
268 requestData["password"] = voicePassword;
269
270 ArrayList SendParams = new ArrayList();
271 SendParams.Add(requestData);
272 XmlRpcRequest updateAccountRequest = new XmlRpcRequest("account_update", SendParams);
273 XmlRpcResponse updateAccountResponse = updateAccountRequest.Send(m_asterisk, m_asterisk_timeout);
274 Hashtable responseData = (Hashtable) updateAccountResponse.Value;
275
276 if (!responseData.ContainsKey("success")) throw new Exception("account_update call failed");
277
278 bool success = Convert.ToBoolean((string) responseData["success"]);
279 if (!success) throw new Exception("account_update failed");
280
281 return r;
282 }
283 catch (Exception e)
284 {
285 m_log.ErrorFormat("[ASTERISKVOICE][CAPS][PROVISIONVOICE]: {0}, retry later", e.Message);
286 m_log.DebugFormat("[ASTERISKVOICE][CAPS][PROVISIONVOICE]: {0} failed", e.ToString());
287
288 return "<llsd>undef</llsd>";
289 }
290 }
291 }
292}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs
new file mode 100644
index 0000000..3e8a433
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/SIPVoice/SIPVoiceModule.cs
@@ -0,0 +1,202 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Reflection;
31using OpenMetaverse;
32using log4net;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications.Cache;
36using OpenSim.Framework.Communications.Capabilities;
37using OpenSim.Framework.Servers;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using Caps=OpenSim.Framework.Communications.Capabilities.Caps;
41
42namespace OpenSim.Region.OptionalModules.Avatar.Voice.SIPVoice
43{
44 public class SIPVoiceModule : IRegionModule
45 {
46 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private static readonly string m_parcelVoiceInfoRequestPath = "0007/";
50 private static readonly string m_provisionVoiceAccountRequestPath = "0008/";
51 private IConfig m_config;
52 private Scene m_scene;
53 private string m_sipDomain;
54
55 #region IRegionModule Members
56
57 public void Initialise(Scene scene, IConfigSource config)
58 {
59 m_scene = scene;
60 m_config = config.Configs["Voice"];
61
62 if (null == m_config || !m_config.GetBoolean("enabled", false))
63 {
64 m_log.Info("[VOICE] plugin disabled");
65 return;
66 }
67 m_log.Info("[VOICE] plugin enabled");
68
69 m_sipDomain = m_config.GetString("sip_domain", String.Empty);
70 if (String.IsNullOrEmpty(m_sipDomain))
71 {
72 m_log.Error("[VOICE] plugin mis-configured: missing sip_domain configuration");
73 m_log.Info("[VOICE] plugin disabled");
74 return;
75 }
76 m_log.InfoFormat("[VOICE] using SIP domain {0}", m_sipDomain);
77
78 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
79 }
80
81 public void PostInitialise()
82 {
83 }
84
85 public void Close()
86 {
87 }
88
89 public string Name
90 {
91 get { return "VoiceModule"; }
92 }
93
94 public bool IsSharedModule
95 {
96 get { return false; }
97 }
98
99 #endregion
100
101 public void OnRegisterCaps(UUID agentID, Caps caps)
102 {
103 m_log.DebugFormat("[VOICE] OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
104 string capsBase = "/CAPS/" + caps.CapsObjectPath;
105 caps.RegisterHandler("ParcelVoiceInfoRequest",
106 new RestStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath,
107 delegate(string request, string path, string param,
108 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
109 {
110 return ParcelVoiceInfoRequest(request, path, param,
111 agentID, caps);
112 }));
113 caps.RegisterHandler("ProvisionVoiceAccountRequest",
114 new RestStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath,
115 delegate(string request, string path, string param,
116 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
117 {
118 return ProvisionVoiceAccountRequest(request, path, param,
119 agentID, caps);
120 }));
121 }
122
123 /// <summary>
124 /// Callback for a client request for ParcelVoiceInfo
125 /// </summary>
126 /// <param name="request"></param>
127 /// <param name="path"></param>
128 /// <param name="param"></param>
129 /// <param name="agentID"></param>
130 /// <param name="caps"></param>
131 /// <returns></returns>
132 public string ParcelVoiceInfoRequest(string request, string path, string param,
133 UUID agentID, Caps caps)
134 {
135 try
136 {
137 m_log.DebugFormat("[VOICE][PARCELVOICE]: request: {0}, path: {1}, param: {2}", request, path, param);
138
139 // FIXME: get the creds from region file or from config
140 Hashtable creds = new Hashtable();
141
142 creds["channel_uri"] = String.Format("sip:{0}@{1}", agentID, m_sipDomain);
143
144 string regionName = m_scene.RegionInfo.RegionName;
145 ScenePresence avatar = m_scene.GetScenePresence(agentID);
146 if (null == m_scene.LandChannel) throw new Exception("land data not yet available");
147 LandData land = m_scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
148
149 LLSDParcelVoiceInfoResponse parcelVoiceInfo =
150 new LLSDParcelVoiceInfoResponse(regionName, land.LocalID, creds);
151
152 string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo);
153 m_log.DebugFormat("[VOICE][PARCELVOICE]: {0}", r);
154
155 return r;
156 }
157 catch (Exception e)
158 {
159 m_log.ErrorFormat("[CAPS]: {0}, try again later", e.ToString());
160 }
161
162 return null;
163 }
164
165 /// <summary>
166 /// Callback for a client request for Voice Account Details
167 /// </summary>
168 /// <param name="request"></param>
169 /// <param name="path"></param>
170 /// <param name="param"></param>
171 /// <param name="agentID"></param>
172 /// <param name="caps"></param>
173 /// <returns></returns>
174 public string ProvisionVoiceAccountRequest(string request, string path, string param,
175 UUID agentID, Caps caps)
176 {
177 try
178 {
179 m_log.DebugFormat("[VOICE][PROVISIONVOICE]: request: {0}, path: {1}, param: {2}",
180 request, path, param);
181
182 string voiceUser = "x" + Convert.ToBase64String(agentID.GetBytes());
183 voiceUser = voiceUser.Replace('+', '-').Replace('/', '_');
184
185 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID);
186 if (null == userInfo) throw new Exception("cannot get user details");
187
188 LLSDVoiceAccountResponse voiceAccountResponse =
189 new LLSDVoiceAccountResponse(voiceUser, "$1$" + userInfo.UserProfile.PasswordHash);
190 string r = LLSDHelpers.SerialiseLLSDReply(voiceAccountResponse);
191 m_log.DebugFormat("[CAPS][PROVISIONVOICE]: {0}", r);
192 return r;
193 }
194 catch (Exception e)
195 {
196 m_log.ErrorFormat("[CAPS][PROVISIONVOICE]: {0}, retry later", e.Message);
197 }
198
199 return null;
200 }
201 }
202}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/AuraMetaEntity.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/AuraMetaEntity.cs
new file mode 100644
index 0000000..d4acc34
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/AuraMetaEntity.cs
@@ -0,0 +1,161 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// AuraMetaEntity.cs created with MonoDevelop
31// User: bongiojp at 3:03 PM 8/6/2008
32//
33// To change standard headers go to Edit->Preferences->Coding->Standard Headers
34//
35
36#endregion Header
37
38using System;
39using System.Collections.Generic;
40using System.Drawing;
41
42using OpenMetaverse;
43
44using Nini.Config;
45
46using OpenSim.Framework;
47using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Region.Physics.Manager;
50
51using log4net;
52
53namespace OpenSim.Region.OptionalModules.ContentManagement
54{
55 public class AuraMetaEntity : PointMetaEntity
56 {
57 #region Constructors
58
59 //transparency of root part, NOT particle system. Should probably add support for changing particle system transparency.
60 public AuraMetaEntity(Scene scene, Vector3 groupPos, float transparency, Vector3 color, Vector3 scale)
61 : base(scene, groupPos, transparency)
62 {
63 SetAura(color, scale);
64 }
65
66 public AuraMetaEntity(Scene scene, UUID uuid, Vector3 groupPos, float transparency, Vector3 color, Vector3 scale)
67 : base(scene, uuid, groupPos, transparency)
68 {
69 SetAura(color, scale);
70 }
71
72 #endregion Constructors
73
74 #region Private Methods
75
76 private float Average(Vector3 values)
77 {
78 return (values.X + values.Y + values.Z)/3f;
79 }
80
81 #endregion Private Methods
82
83 #region Public Methods
84
85 public void SetAura(Vector3 color, Vector3 scale)
86 {
87 SetAura(color, Average(scale) * 2.0f);
88 }
89
90 public void SetAura(Vector3 color, float radius)
91 {
92 SceneObjectPart From = m_Entity.RootPart;
93
94 //m_log.Debug("[META ENTITY] BEFORE: radius = " + radius);
95 float burstRadius = 0.1f;
96 Primitive.ParticleSystem.SourcePattern patternFlags = Primitive.ParticleSystem.SourcePattern.None;
97 float age = 1.5f;
98 float burstRate = 0.4f;
99 if (radius >= 8.0f)
100 {
101 //float sizeOfObject = radius / 2.0f;
102 burstRadius = (radius - 8.0f)/3f;
103 burstRate = 1.5f;
104 radius = 7.99f;
105 patternFlags = Primitive.ParticleSystem.SourcePattern.Explode;
106 age = 4.0f;
107 }
108 SetAura(From, color, radius, burstRadius, age, burstRate, patternFlags);
109 }
110
111 public void SetAura(SceneObjectPart From, Vector3 color, float radius, float burstRadius, float age, float burstRate, Primitive.ParticleSystem.SourcePattern patternFlags)
112 {
113 Primitive.ParticleSystem prules = new Primitive.ParticleSystem();
114 //prules.PartDataFlags = Primitive.ParticleSystem.ParticleDataFlags.Emissive |
115 // Primitive.ParticleSystem.ParticleDataFlags.FollowSrc; //PSYS_PART_FLAGS
116 //prules.PartDataFlags = Primitive.ParticleSystem.ParticleDataFlags.Beam |
117 // Primitive.ParticleSystem.ParticleDataFlags.TargetPos;
118 prules.PartStartColor.R = color.X; //PSYS_PART_START_COLOR
119 prules.PartStartColor.G = color.Y;
120 prules.PartStartColor.B = color.Z;
121 prules.PartStartColor.A = 0.5f; //PSYS_PART_START_ALPHA, transparency
122 prules.PartEndColor.R = color.X; //PSYS_PART_END_COLOR
123 prules.PartEndColor.G = color.Y;
124 prules.PartEndColor.B = color.Z;
125 prules.PartEndColor.A = 0.5f; //PSYS_PART_END_ALPHA, transparency
126 /*prules.PartStartScaleX = 0.5f; //PSYS_PART_START_SCALE
127 prules.PartStartScaleY = 0.5f;
128 prules.PartEndScaleX = 0.5f; //PSYS_PART_END_SCALE
129 prules.PartEndScaleY = 0.5f;
130 */
131 prules.PartStartScaleX = radius; //PSYS_PART_START_SCALE
132 prules.PartStartScaleY = radius;
133 prules.PartEndScaleX = radius; //PSYS_PART_END_SCALE
134 prules.PartEndScaleY = radius;
135 prules.PartMaxAge = age; //PSYS_PART_MAX_AGE
136 prules.PartAcceleration.X = 0.0f; //PSYS_SRC_ACCEL
137 prules.PartAcceleration.Y = 0.0f;
138 prules.PartAcceleration.Z = 0.0f;
139 prules.Pattern = patternFlags; //PSYS_SRC_PATTERN
140 //prules.Texture = UUID.Zero;//= UUID //PSYS_SRC_TEXTURE, default used if blank
141 prules.BurstRate = burstRate; //PSYS_SRC_BURST_RATE
142 prules.BurstPartCount = 2; //PSYS_SRC_BURST_PART_COUNT
143 //prules.BurstRadius = radius; //PSYS_SRC_BURST_RADIUS
144 prules.BurstRadius = burstRadius; //PSYS_SRC_BURST_RADIUS
145 prules.BurstSpeedMin = 0.001f; //PSYS_SRC_BURST_SPEED_MIN
146 prules.BurstSpeedMax = 0.001f; //PSYS_SRC_BURST_SPEED_MAX
147 prules.MaxAge = 0.0f; //PSYS_SRC_MAX_AGE
148 //prules.Target = To; //PSYS_SRC_TARGET_KEY
149 prules.AngularVelocity.X = 0.0f; //PSYS_SRC_OMEGA
150 prules.AngularVelocity.Y = 0.0f;
151 prules.AngularVelocity.Z = 0.0f;
152 prules.InnerAngle = 0.0f; //PSYS_SRC_ANGLE_BEGIN
153 prules.OuterAngle = 0.0f; //PSYS_SRC_ANGLE_END
154
155 prules.CRC = 1; //activates the particle system??
156 From.AddNewParticleSystem(prules);
157 }
158
159 #endregion Public Methods
160 }
161}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/BeamMetaEntity.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/BeamMetaEntity.cs
new file mode 100644
index 0000000..c0a0603
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/BeamMetaEntity.cs
@@ -0,0 +1,139 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// BeamMetaEntity.cs created with MonoDevelop
31// User: bongiojp at 3:03 PM 8/6/2008
32//
33// To change standard headers go to Edit->Preferences->Coding->Standard Headers
34//
35
36#endregion Header
37
38using System;
39using System.Collections.Generic;
40using System.Drawing;
41
42using OpenMetaverse;
43
44using Nini.Config;
45
46using OpenSim.Framework;
47using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Region.Physics.Manager;
50
51using log4net;
52
53namespace OpenSim.Region.OptionalModules.ContentManagement
54{
55 public class BeamMetaEntity : PointMetaEntity
56 {
57 #region Constructors
58
59 public BeamMetaEntity(Scene scene, Vector3 groupPos, float transparency, SceneObjectPart To, Vector3 color)
60 : base(scene, groupPos, transparency)
61 {
62 SetBeamToUUID(To, color);
63 }
64
65 public BeamMetaEntity(Scene scene, UUID uuid, Vector3 groupPos, float transparency, SceneObjectPart To, Vector3 color)
66 : base(scene, uuid, groupPos, transparency)
67 {
68 SetBeamToUUID(To, color);
69 }
70
71 #endregion Constructors
72
73 #region Public Methods
74
75 public void SetBeamToUUID(SceneObjectPart To, Vector3 color)
76 {
77 SceneObjectPart From = m_Entity.RootPart;
78 //Scale size of particles to distance objects are apart (for better visibility)
79 Vector3 FromPos = From.GetWorldPosition();
80 Vector3 ToPos = From.GetWorldPosition();
81 // UUID toUUID = To.UUID;
82 float distance = (float) (Math.Sqrt(Math.Pow(FromPos.X-ToPos.X, 2) +
83 Math.Pow(FromPos.X-ToPos.Y, 2) +
84 Math.Pow(FromPos.X-ToPos.Z, 2)
85 )
86 );
87 //float rate = (float) (distance/4f);
88 float rate = 0.5f;
89 float scale = (float) (distance/128f);
90 float speed = (float) (2.0f - distance/128f);
91
92 SetBeamToUUID(From, To, color, rate, scale, speed);
93 }
94
95 public void SetBeamToUUID(SceneObjectPart From, SceneObjectPart To, Vector3 color, float rate, float scale, float speed)
96 {
97 Primitive.ParticleSystem prules = new Primitive.ParticleSystem();
98 //prules.PartDataFlags = Primitive.ParticleSystem.ParticleDataFlags.Emissive |
99 // Primitive.ParticleSystem.ParticleDataFlags.FollowSrc; //PSYS_PART_FLAGS
100 prules.PartDataFlags = Primitive.ParticleSystem.ParticleDataFlags.Beam |
101 Primitive.ParticleSystem.ParticleDataFlags.TargetPos;
102 prules.PartStartColor.R = color.X; //PSYS_PART_START_COLOR
103 prules.PartStartColor.G = color.Y;
104 prules.PartStartColor.B = color.Z;
105 prules.PartStartColor.A = 1.0f; //PSYS_PART_START_ALPHA, transparency
106 prules.PartEndColor.R = color.X; //PSYS_PART_END_COLOR
107 prules.PartEndColor.G = color.Y;
108 prules.PartEndColor.B = color.Z;
109 prules.PartEndColor.A = 1.0f; //PSYS_PART_END_ALPHA, transparency
110 prules.PartStartScaleX = scale; //PSYS_PART_START_SCALE
111 prules.PartStartScaleY = scale;
112 prules.PartEndScaleX = scale; //PSYS_PART_END_SCALE
113 prules.PartEndScaleY = scale;
114 prules.PartMaxAge = 1.0f; //PSYS_PART_MAX_AGE
115 prules.PartAcceleration.X = 0.0f; //PSYS_SRC_ACCEL
116 prules.PartAcceleration.Y = 0.0f;
117 prules.PartAcceleration.Z = 0.0f;
118 //prules.Pattern = Primitive.ParticleSystem.SourcePattern.Explode; //PSYS_SRC_PATTERN
119 //prules.Texture = UUID.Zero;//= UUID //PSYS_SRC_TEXTURE, default used if blank
120 prules.BurstRate = rate; //PSYS_SRC_BURST_RATE
121 prules.BurstPartCount = 1; //PSYS_SRC_BURST_PART_COUNT
122 prules.BurstRadius = 0.5f; //PSYS_SRC_BURST_RADIUS
123 prules.BurstSpeedMin = speed; //PSYS_SRC_BURST_SPEED_MIN
124 prules.BurstSpeedMax = speed; //PSYS_SRC_BURST_SPEED_MAX
125 prules.MaxAge = 0.0f; //PSYS_SRC_MAX_AGE
126 prules.Target = To.UUID; //PSYS_SRC_TARGET_KEY
127 prules.AngularVelocity.X = 0.0f; //PSYS_SRC_OMEGA
128 prules.AngularVelocity.Y = 0.0f;
129 prules.AngularVelocity.Z = 0.0f;
130 prules.InnerAngle = 0.0f; //PSYS_SRC_ANGLE_BEGIN
131 prules.OuterAngle = 0.0f; //PSYS_SRC_ANGLE_END
132
133 prules.CRC = 1; //activates the particle system??
134 From.AddNewParticleSystem(prules);
135 }
136
137 #endregion Public Methods
138 }
139}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMController.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMController.cs
new file mode 100644
index 0000000..80989a7
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMController.cs
@@ -0,0 +1,757 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// CMController.cs
31// User: bongiojp
32//
33
34#endregion Header
35
36using System;
37using System.Collections;
38using System.Collections.Generic;
39using System.Diagnostics;
40using System.Threading;
41
42using OpenMetaverse;
43
44using OpenSim;
45using OpenSim.Framework;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Physics.Manager;
49
50using log4net;
51
52namespace OpenSim.Region.OptionalModules.ContentManagement
53{
54 /// <summary>
55 /// The controller in a Model-View-Controller framework. This controller catches actions by the avatars, creates work packets, loops through these work packets in a separate thread,
56 /// then dictates to the model how the data should change and dictates to the view which data should be displayed. The main mechanism for interaction is through the simchat system.
57 /// </summary>
58 public class CMController
59 {
60 #region Static Fields
61
62 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
63
64 /// <value>
65 /// The queue that keeps track of which actions have happened. The MainLoop thread eats through this queue.
66 /// </value>
67 private static OpenSim.Framework.BlockingQueue<Work> m_WorkQueue = new OpenSim.Framework.BlockingQueue<Work>();
68
69 #endregion Static Fields
70
71 #region Fields
72
73 //bool init = false;
74 int m_channel = -1;
75
76 /// <value>
77 /// The estate module is used to identify which clients are estateManagers. Presently, the controller only pays attention to estate managers.
78 /// </value>
79 IEstateModule m_estateModule = null;
80
81 //These have to be global variables, threading doesn't allow for passing parameters. (Used in MainLoop)
82 CMModel m_model = null;
83
84 /// <value>
85 /// A list of all the scenes that should be revisioned. Controller is the only class that keeps track of all scenes in the region.
86 /// </value>
87 Hashtable m_sceneList = Hashtable.Synchronized(new Hashtable());
88 State m_state = State.NONE;
89 Thread m_thread = null;
90 CMView m_view = null;
91
92 #endregion Fields
93
94 #region Constructors
95
96 /// <summary>
97 /// Initializes a work thread with an initial scene. Additional scenes should be added through the RegisterNewRegion method.
98 /// </summary>
99 /// <param name="model">
100 /// <see cref="CMModel"/>
101 /// </param>
102 /// <param name="view">
103 /// <see cref="CMView"/>
104 /// </param>
105 /// <param name="scene">
106 /// The first scene to keep track of. <see cref="Scene"/>
107 /// </param>
108 /// <param name="channel">
109 /// The simchat channel number to listen to for instructions <see cref="System.Int32"/>
110 /// </param>
111 public CMController(CMModel model, CMView view, Scene scene, int channel)
112 {
113 m_model = model; m_view = view; m_channel = channel;
114 RegisterNewRegion(scene);
115 Initialize(model, view, scene, channel);
116 }
117
118 #endregion Constructors
119
120 #region Private Methods
121
122 //------------------------------------------------ EVENTS ----------------------------------------------------//
123// private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, LLUUID regionID)
124// {
125// }
126
127 /// <summary>
128 /// Searches in all scenes for a SceneObjectGroup that contains a part with a specific localID. If found, the object is returned. Else null is returned.
129 /// </summary>
130 private SceneObjectGroup GetGroupByPrim(uint localID)
131 {
132 foreach (Object currScene in m_sceneList.Values)
133 {
134 foreach (EntityBase ent in ((Scene)currScene).GetEntities())
135 {
136 if (ent is SceneObjectGroup)
137 {
138 if (((SceneObjectGroup)ent).HasChildPrim(localID))
139 return (SceneObjectGroup)ent;
140 }
141 }
142 }
143 return null;
144 }
145
146 private void Initialize(CMModel model, CMView view, Scene scene, int channel)
147 {
148 lock (this)
149 {
150 m_estateModule = scene.RequestModuleInterface<IEstateModule>();
151 m_thread = new Thread(MainLoop);
152 m_thread.Name = "Content Management";
153 m_thread.IsBackground = true;
154 m_thread.Start();
155 ThreadTracker.Add(m_thread);
156 m_state = State.NONE;
157 }
158 }
159
160 /// <summary>
161 /// Run in a thread of its own. A endless loop that consumes (or blocks on) and work queue. Thw work queue is filled through client actions.
162 /// </summary>
163 private void MainLoop()
164 {
165 try
166 {
167 CMModel model = m_model; CMView view = m_view; int channel = m_channel;
168 Work currentJob = new Work();
169 while (true)
170 {
171 currentJob = m_WorkQueue.Dequeue();
172 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- DeQueued a request");
173 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- Work type: " + currentJob.Type);
174 switch (currentJob.Type)
175 {
176 case WorkType.NONE:
177 break;
178 case WorkType.OBJECTATTRIBUTECHANGE:
179 ObjectAttributeChanged(model, view, currentJob.LocalId);
180 break;
181 case WorkType.PRIMITIVEADDED:
182 PrimitiveAdded(model, view, currentJob);
183 break;
184 case WorkType.OBJECTDUPLICATED:
185 ObjectDuplicated(model, view, currentJob.LocalId);
186 break;
187 case WorkType.OBJECTKILLED:
188 ObjectKilled(model, view, (SceneObjectGroup) currentJob.Data1);
189 break;
190 case WorkType.UNDODID:
191 UndoDid(model, view, currentJob.UUID);
192 break;
193 case WorkType.NEWCLIENT:
194 NewClient(view, (IClientAPI) currentJob.Data1);
195 break;
196 case WorkType.SIMCHAT:
197 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- Message received: " + ((OSChatMessage) currentJob.Data1).Message);
198 SimChat(model, view, (OSChatMessage) currentJob.Data1, channel);
199 break;
200 default:
201 m_log.Debug("[CONTENT MANAGEMENT] MAIN LOOP -- uuuuuuuuuh, what?");
202 break;
203 }
204 }
205 }
206 catch (Exception e)
207 {
208 // TODO: Let users in the sim and those entering it and possibly an external watchdog know what has happened
209 m_log.ErrorFormat(
210 "[CONTENT MANAGEMENT]: Content management thread terminating with exception. PLEASE REBOOT YOUR SIM - CONTENT MANAGEMENT WILL NOT BE AVAILABLE UNTIL YOU DO. Exception is {0}",
211 e);
212 }
213 }
214
215 /// <summary>
216 /// Only called by the MainLoop. Updates the view of a new client with metaentities if diff-mode is currently enabled.
217 /// </summary>
218 private void NewClient(CMView view, IClientAPI client)
219 {
220 if ((m_state & State.SHOWING_CHANGES) > 0)
221 view.SendMetaEntitiesToNewClient(client);
222 }
223
224 /// <summary>
225 /// Only called by the MainLoop.
226 /// </summary>
227 private void ObjectAttributeChanged(CMModel model, CMView view, uint LocalId)
228 {
229 SceneObjectGroup group = null;
230 if ((m_state & State.SHOWING_CHANGES) > 0)
231 {
232 group = GetGroupByPrim(LocalId);
233 if (group != null)
234 {
235 view.DisplayAuras(model.UpdateNormalEntityEffects(group)); //Might be a normal entity (green aura)
236 m_view.DisplayMetaEntity(group.UUID); //Might be a meta entity (blue aura)
237 }
238 }
239 }
240
241 /// <summary>
242 /// Only called by the MainLoop. Displays new green auras over the newly created part when a part is shift copied.
243 /// </summary>
244 private void ObjectDuplicated(CMModel model, CMView view, uint localId)
245 {
246 if ((m_state & State.SHOWING_CHANGES) > 0)
247 view.DisplayAuras(model.CheckForNewEntitiesMissingAuras(GetGroupByPrim(localId).Scene));
248 }
249
250 /// <summary>
251 /// Only called by the MainLoop.
252 /// </summary>
253 private void ObjectKilled(CMModel model, CMView view, SceneObjectGroup group)
254 {
255 if ((m_state & State.SHOWING_CHANGES) > 0)
256 {
257 view.RemoveOrUpdateDeletedEntity(group);
258 model.RemoveOrUpdateDeletedEntity(group);
259 }
260 }
261
262 /// <summary>
263 /// Only called by the MainLoop.
264 /// </summary>
265 private void PrimitiveAdded(CMModel model, CMView view, Work currentJob)
266 {
267 if ((m_state & State.SHOWING_CHANGES) > 0)
268 {
269 foreach (Object scene in m_sceneList.Values)
270 m_view.DisplayAuras(model.CheckForNewEntitiesMissingAuras((Scene) scene));
271 }
272 }
273
274 /// <summary>
275 /// Only called by the MainLoop.
276 /// </summary>
277 private void UndoDid(CMModel model, CMView view, UUID uuid)
278 {
279 if ((m_state & State.SHOWING_CHANGES) > 0)
280 {
281 ContentManagementEntity ent = model.FindMetaEntityAffectedByUndo(uuid);
282 if (ent != null)
283 view.DisplayEntity(ent);
284 }
285 }
286
287 #endregion Private Methods
288
289 #region Protected Methods
290
291 protected void GroupBeingDeleted(SceneObjectGroup group)
292 {
293 m_log.Debug("[CONTENT MANAGEMENT] Something was deleted!!!");
294 Work moreWork = new Work();
295 moreWork.Type = WorkType.OBJECTKILLED;
296 moreWork.Data1 = group.Copy();
297 m_WorkQueue.Enqueue(moreWork);
298 }
299
300 protected void ObjectDuplicated(uint localID, Vector3 offset, uint dupeFlags, UUID AgentID, UUID GroupID)
301 {
302 Work moreWork = new Work();
303 moreWork.Type = WorkType.OBJECTDUPLICATED;
304 moreWork.LocalId = localID;
305 m_WorkQueue.Enqueue(moreWork);
306 m_log.Debug("[CONTENT MANAGEMENT] dup queue");
307 }
308
309 protected void ObjectDuplicatedOnRay(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID,
310 UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart,
311 bool BypassRaycast, bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates)
312 {
313 Work moreWork = new Work();
314 moreWork.Type = WorkType.OBJECTDUPLICATED;
315 moreWork.LocalId = localID;
316 m_WorkQueue.Enqueue(moreWork);
317 m_log.Debug("[CONTENT MANAGEMENT] dup queue");
318 }
319
320 protected void OnNewClient(IClientAPI client)
321 {
322 Work moreWork = new Work();
323 moreWork.Type = WorkType.NEWCLIENT;
324 moreWork.Data1 = client;
325 m_WorkQueue.Enqueue(moreWork);
326 m_log.Debug("[CONTENT MANAGEMENT] new client");
327 }
328
329 protected void OnUnDid(IClientAPI remoteClient, UUID primId)
330 {
331 Work moreWork = new Work();
332 moreWork.Type = WorkType.UNDODID;
333 moreWork.UUID = primId;
334 m_WorkQueue.Enqueue(moreWork);
335 m_log.Debug("[CONTENT MANAGEMENT] undid");
336 }
337
338 /// <summary>
339 /// Takes a list of scenes and forms a new orderd list according to the proximity of scenes to the second argument.
340 /// </summary>
341 protected static System.Collections.Generic.List<Scene> ScenesInOrderOfProximity(Hashtable sceneList, Scene scene)
342 {
343 int somethingAddedToList = 1;
344 System.Collections.Generic.List<Scene> newList = new List<Scene>();
345 newList.Add(scene);
346
347 if (!sceneList.ContainsValue(scene))
348 {
349 foreach (Object sceneObj in sceneList)
350 newList.Add((Scene) sceneObj);
351 return newList;
352 }
353
354 while (somethingAddedToList > 0)
355 {
356 somethingAddedToList = 0;
357 for (int i = 0; i < newList.Count; i++)
358 {
359 foreach (Object sceneObj in sceneList.Values)
360 {
361 if (newList[i].CheckNeighborRegion(((Scene)sceneObj).RegionInfo) && (!newList.Contains((Scene)sceneObj)))
362 {
363 newList.Add((Scene)sceneObj);
364 somethingAddedToList++;
365 }
366 }
367 }
368 }
369
370 foreach (Object sceneObj in sceneList.Values)
371 if (!newList.Contains((Scene)sceneObj))
372 newList.Add((Scene)sceneObj);
373
374 return newList;
375 }
376
377 //This is stupid, the same information is contained in the first and second argument
378 protected void SimChatSent(Object x, OSChatMessage e)
379 {
380 m_log.Debug("[CONTENT MANAGEMENT] SIMCHAT SENT !!!!!!!");
381 m_log.Debug("[CONTENT MANAGEMENT] message was: " + e.Message);
382 Work moreWork = new Work();
383 moreWork.Type = WorkType.SIMCHAT;
384 moreWork.Data1 = e;
385 m_WorkQueue.Enqueue(moreWork);
386 }
387
388 /// <summary>
389 /// Adds extra handlers to a number of events so that the controller can produce work based on the client's actions.
390 /// </summary>
391 protected void StartManaging(IClientAPI client)
392 {
393 m_log.Debug("[CONTENT MANAGEMENT] Registering channel with chat services.");
394 // client.OnChatFromClient += SimChatSent;
395 //init = true;
396
397 OnNewClient(client);
398
399 m_log.Debug("[CONTENT MANAGEMENT] Adding handlers to client.");
400 client.OnUpdatePrimScale += UpdateSingleScale;
401 client.OnUpdatePrimGroupScale += UpdateMultipleScale;
402 client.OnUpdatePrimGroupPosition += UpdateMultiplePosition;
403 client.OnUpdatePrimSinglePosition += UpdateSinglePosition;
404 client.OnUpdatePrimGroupRotation += UpdateMultipleRotation;
405 client.OnUpdatePrimSingleRotation += UpdateSingleRotation;
406 client.OnAddPrim += UpdateNewParts;
407 client.OnObjectDuplicate += ObjectDuplicated;
408 client.OnObjectDuplicateOnRay += ObjectDuplicatedOnRay;
409 client.OnUndo += OnUnDid;
410 //client.OnUpdatePrimGroupMouseRotation += m_innerScene.UpdatePrimRotation;
411 }
412
413 /// <summary>
414 ///
415 /// </summary>
416 protected void StopManaging(UUID clientUUID)
417 {
418 foreach (Object sceneobj in m_sceneList.Values)
419 {
420 ScenePresence presence = ((Scene)sceneobj).GetScenePresence(clientUUID);
421 if (presence != null)
422 {
423 IClientAPI client = presence.ControllingClient;
424 m_log.Debug("[CONTENT MANAGEMENT] Unregistering channel with chat services.");
425 // client.OnChatFromViewer -= SimChatSent;
426
427 m_log.Debug("[CONTENT MANAGEMENT] Removing handlers to client");
428 client.OnUpdatePrimScale -= UpdateSingleScale;
429 client.OnUpdatePrimGroupScale -= UpdateMultipleScale;
430 client.OnUpdatePrimGroupPosition -= UpdateMultiplePosition;
431 client.OnUpdatePrimSinglePosition -= UpdateSinglePosition;
432 client.OnUpdatePrimGroupRotation -= UpdateMultipleRotation;
433 client.OnUpdatePrimSingleRotation -= UpdateSingleRotation;
434 client.OnAddPrim -= UpdateNewParts;
435 client.OnObjectDuplicate -= ObjectDuplicated;
436 client.OnObjectDuplicateOnRay -= ObjectDuplicatedOnRay;
437 client.OnUndo -= OnUnDid;
438 //client.OnUpdatePrimGroupMouseRotation += m_innerScene.UpdatePrimRotation;
439 return;
440 }
441 }
442 }
443
444 protected void UpdateMultiplePosition(uint localID, Vector3 pos, IClientAPI remoteClient)
445 {
446 Work moreWork = new Work();
447 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
448 moreWork.LocalId = localID;
449 m_WorkQueue.Enqueue(moreWork);
450 m_log.Debug("[CONTENT MANAGEMENT] pos");
451 }
452
453 protected void UpdateMultipleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
454 {
455 Work moreWork = new Work();
456 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
457 moreWork.LocalId = localID;
458 m_WorkQueue.Enqueue(moreWork);
459 m_log.Debug("[CONTENT MANAGEMENT] rot");
460 }
461
462 protected void UpdateMultipleScale(uint localID, Vector3 scale, IClientAPI remoteClient)
463 {
464 Work moreWork = new Work();
465 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
466 moreWork.LocalId = localID;
467 m_WorkQueue.Enqueue(moreWork);
468 m_log.Debug("[CONTENT MANAGEMENT]scale");
469 }
470
471 protected void UpdateNewParts(UUID ownerID, UUID groupID, Vector3 RayEnd, Quaternion rot, PrimitiveBaseShape shape,
472 byte bypassRaycast, Vector3 RayStart, UUID RayTargetID,
473 byte RayEndIsIntersection)
474 {
475 Work moreWork = new Work();
476 moreWork.Type = WorkType.PRIMITIVEADDED;
477 moreWork.UUID = ownerID;
478 m_WorkQueue.Enqueue(moreWork);
479 m_log.Debug("[CONTENT MANAGEMENT] new parts");
480 }
481
482 protected void UpdateSinglePosition(uint localID, Vector3 pos, IClientAPI remoteClient)
483 {
484 Work moreWork = new Work();
485 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
486 moreWork.LocalId = localID;
487 m_WorkQueue.Enqueue(moreWork);
488 m_log.Debug("[CONTENT MANAGEMENT] move");
489 }
490
491 /// <summary>
492 ///
493 /// </summary>
494 protected void UpdateSingleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
495 {
496 Work moreWork = new Work();
497 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
498 moreWork.LocalId = localID;
499 m_WorkQueue.Enqueue(moreWork);
500 m_log.Debug("[CONTENT MANAGEMENT] rot");
501 }
502
503 protected void UpdateSingleScale(uint localID, Vector3 scale, IClientAPI remoteClient)
504 {
505 Work moreWork = new Work();
506 moreWork.Type = WorkType.OBJECTATTRIBUTECHANGE;
507 moreWork.LocalId = localID;
508 m_WorkQueue.Enqueue(moreWork);
509 m_log.Debug("[CONTENT MANAGEMENT] scale");
510 }
511
512 /// <summary>
513 /// Only called from within the SimChat method.
514 /// </summary>
515 protected void commit(string message, Scene scene, CMModel model, CMView view)
516 {
517 System.Collections.Generic.List<Scene> proximitySceneList = ScenesInOrderOfProximity(m_sceneList, scene);
518
519 string[] args = message.Split(new char[] {' '});
520
521 char[] logMessage = {' '};
522 if (args.Length > 1)
523 {
524 logMessage = new char[message.Length - (args[0].Length)];
525 message.CopyTo(args[0].Length, logMessage, 0, message.Length - (args[0].Length));
526 }
527
528 m_log.Debug("[CONTENT MANAGEMENT] Saving terrain and objects of region.");
529 foreach (Scene currScene in proximitySceneList)
530 {
531 model.CommitRegion(currScene, new String(logMessage));
532 view.SendSimChatMessage(scene, "Region Saved Successfully: " + currScene.RegionInfo.RegionName);
533 }
534
535 view.SendSimChatMessage(scene, "Successfully saved all regions.");
536 m_state |= State.DIRTY;
537
538 if ((m_state & State.SHOWING_CHANGES) > 0) //DISPLAY NEW CHANGES INSTEAD OF OLD CHANGES
539 {
540 view.SendSimChatMessage(scene, "Updating differences between new revision and current environment.");
541 //Hide objects from users and Forget about them
542 view.HideAllMetaEntities();
543 view.HideAllAuras();
544 model.DeleteAllMetaObjects();
545
546 //Recreate them from backend files
547 foreach (Scene currScene in proximitySceneList)
548 {
549 model.UpdateCMEntities(currScene);
550 view.SendSimChatMessage(scene, "Finished updating differences between current scene and last revision: " + currScene.RegionInfo.RegionName);
551 }
552
553 //Display new objects to users1
554 view.DisplayRecentChanges();
555 view.SendSimChatMessage(scene, "Finished updating for DIFF-MODE.");
556 m_state &= ~(State.DIRTY);
557 m_state |= State.SHOWING_CHANGES;
558 }
559 }
560
561 /// <summary>
562 /// Only called from within the SimChat method.
563 /// </summary>
564 protected void diffmode(Scene scene, CMModel model, CMView view)
565 {
566 System.Collections.Generic.List<Scene> proximitySceneList = ScenesInOrderOfProximity(m_sceneList, scene);
567
568 if ((m_state & State.SHOWING_CHANGES) > 0) // TURN OFF
569 {
570 view.SendSimChatMessage(scene, "Hiding all meta objects.");
571 view.HideAllMetaEntities();
572 view.HideAllAuras();
573 view.SendSimChatMessage(scene, "Diff-mode = OFF");
574
575 m_state &= ~State.SHOWING_CHANGES;
576 return;
577 }
578 else // TURN ON
579 {
580 if ((m_state & State.DIRTY) != 0 || m_state == State.NONE)
581 {
582 view.SendSimChatMessage(scene, "Hiding meta objects and replacing with latest revision");
583 //Hide objects from users and Forget about them
584 view.HideAllMetaEntities();
585 view.HideAllAuras();
586 model.DeleteAllMetaObjects();
587 //Recreate them from backend files
588 foreach (Object currScene in m_sceneList.Values)
589 model.UpdateCMEntities((Scene) currScene);
590 }
591 else if ((m_state & State.DIRTY) != 0) {
592 view.SendSimChatMessage(scene, "Forming list of meta entities with latest revision");
593 foreach (Scene currScene in proximitySceneList)
594 model.UpdateCMEntities(currScene);
595 }
596
597 view.SendSimChatMessage(scene, "Displaying differences between last revision and current environment");
598 foreach (Scene currScene in proximitySceneList)
599 model.CheckForNewEntitiesMissingAuras(currScene);
600 view.DisplayRecentChanges();
601
602 view.SendSimChatMessage(scene, "Diff-mode = ON");
603 m_state |= State.SHOWING_CHANGES;
604 m_state &= ~State.DIRTY;
605 }
606 }
607
608 /// <summary>
609 /// Only called from within the SimChat method. Hides all auras and meta entities,
610 /// retrieves the current scene object list with the most recent revision retrieved from the model for each scene,
611 /// then lets the view update the clients of the new objects.
612 /// </summary>
613 protected void rollback(Scene scene, CMModel model, CMView view)
614 {
615 if ((m_state & State.SHOWING_CHANGES) > 0)
616 {
617 view.HideAllAuras();
618 view.HideAllMetaEntities();
619 }
620
621 System.Collections.Generic.List<Scene> proximitySceneList = ScenesInOrderOfProximity(m_sceneList, scene);
622 foreach (Scene currScene in proximitySceneList)
623 model.RollbackRegion(currScene);
624
625 if ((m_state & State.DIRTY) != 0)
626 {
627 model.DeleteAllMetaObjects();
628 foreach (Scene currScene in proximitySceneList)
629 model.UpdateCMEntities(currScene);
630 }
631
632 if ((m_state & State.SHOWING_CHANGES) > 0)
633 view.DisplayRecentChanges();
634 }
635
636 #endregion Protected Methods
637
638 #region Public Methods
639
640 /// <summary>
641 /// Register a new scene object to keep track of for revisioning. Starts the controller monitoring actions of clients within the given scene.
642 /// </summary>
643 /// <param name="scene">
644 /// A <see cref="Scene"/>
645 /// </param>
646 public void RegisterNewRegion(Scene scene)
647 {
648 m_sceneList.Add(scene.RegionInfo.RegionID, scene);
649
650 m_log.Debug("[CONTENT MANAGEMENT] Registering new region: " + scene.RegionInfo.RegionID);
651 m_log.Debug("[CONTENT MANAGEMENT] Initializing Content Management System.");
652
653 scene.EventManager.OnNewClient += StartManaging;
654 scene.EventManager.OnChatFromClient += SimChatSent;
655 scene.EventManager.OnRemovePresence += StopManaging;
656 // scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
657 scene.EventManager.OnObjectBeingRemovedFromScene += GroupBeingDeleted;
658 }
659
660 /// <summary>
661 /// Only called by the MainLoop. Takes the message from a user sent to the channel and executes the proper command.
662 /// </summary>
663 public void SimChat(CMModel model, CMView view, OSChatMessage e, int channel)
664 {
665 if (e.Channel != channel)
666 return;
667 if (e.Sender == null)
668 return;
669
670 m_log.Debug("[CONTENT MANAGEMENT] Message received: " + e.Message);
671
672 IClientAPI client = e.Sender;
673 Scene scene = (Scene) e.Scene;
674 string message = e.Message;
675 string[] args = e.Message.Split(new char[] {' '});
676
677 ScenePresence avatar = scene.GetScenePresence(client.AgentId);
678
679 if (!(m_estateModule.IsManager(avatar.UUID)))
680 {
681 m_log.Debug("[CONTENT MANAGEMENT] Message sent from non Estate Manager ... ignoring.");
682 view.SendSimChatMessage(scene, "You must be an estate manager to perform that action.");
683 return;
684 }
685
686 switch (args[0])
687 {
688 case "ci":
689 case "commit":
690 commit(message, scene, model, view);
691 break;
692 case "dm":
693 case "diff-mode":
694 diffmode(scene, model, view);
695 break;
696 case "rb":
697 case "rollback":
698 rollback(scene, model, view);
699 break;
700 case "help":
701 m_view.DisplayHelpMenu(scene);
702 break;
703 default:
704 view.SendSimChatMessage(scene, "Command not found: " + args[0]);
705 break;
706 }
707 }
708
709 #endregion Public Methods
710
711 #region Other
712
713 /// <value>
714 /// Used to keep track of whether a list has been produced yet and whether that list is up-to-date compard to latest revision on disk.
715 /// </value>
716 [Flags]
717 private enum State
718 {
719 NONE = 0,
720 DIRTY = 1, // The meta entities may not correctly represent the last revision.
721 SHOWING_CHANGES = 1<<1 // The meta entities are being shown to user.
722 }
723
724 /// <value>
725 /// The structure that defines the basic unit of work which is produced when a user sends commands to the ContentMangaementSystem.
726 /// </value>
727 private struct Work
728 {
729 #region Fields
730
731 public Object Data1; //Just space for holding data.
732 public Object Data2; //Just more space for holding data.
733 public uint LocalId; //Convenient
734 public WorkType Type;
735 public UUID UUID; //Convenient
736
737 #endregion Fields
738 }
739
740 /// <value>
741 /// Identifies what the data in struct Work should be used for.
742 /// </value>
743 private enum WorkType
744 {
745 NONE,
746 OBJECTATTRIBUTECHANGE,
747 PRIMITIVEADDED,
748 OBJECTDUPLICATED,
749 OBJECTKILLED,
750 UNDODID,
751 NEWCLIENT,
752 SIMCHAT
753 }
754
755 #endregion Other
756 }
757}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMEntityCollection.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMEntityCollection.cs
new file mode 100644
index 0000000..d5cf596
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMEntityCollection.cs
@@ -0,0 +1,193 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// CMEntityCollection.cs created with MonoDevelop
31// User: bongiojp at 10:09 AM 7/7/2008
32//
33// Creates, Deletes, Stores ContentManagementEntities
34//
35
36#endregion Header
37
38using System;
39using System.Collections;
40using System.Collections.Generic;
41using System.Threading;
42
43using OpenMetaverse;
44
45using Nini.Config;
46
47using OpenSim;
48using OpenSim.Framework;
49using OpenSim.Region.Framework.Interfaces;
50using OpenSim.Region.Framework.Scenes;
51using OpenSim.Region.Physics.Manager;
52
53using log4net;
54
55namespace OpenSim.Region.OptionalModules.ContentManagement
56{
57 public class CMEntityCollection
58 {
59 #region Fields
60
61 // private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
62 // Any ContentManagementEntities that represent old versions of current SceneObjectGroups or
63 // old versions of deleted SceneObjectGroups will be stored in this hash table.
64 // The UUID keys are from the SceneObjectGroup RootPart UUIDs
65 protected Hashtable m_CMEntityHash = Hashtable.Synchronized(new Hashtable()); //UUID to ContentManagementEntity
66
67 // SceneObjectParts that have not been revisioned will be given green auras stored in this hashtable
68 // The UUID keys are from the SceneObjectPart that they are supposed to be on.
69 protected Hashtable m_NewlyCreatedEntityAura = Hashtable.Synchronized(new Hashtable()); //UUID to AuraMetaEntity
70
71 #endregion Fields
72
73 #region Constructors
74
75 public CMEntityCollection()
76 {
77 }
78
79 #endregion Constructors
80
81 #region Public Properties
82
83 public Hashtable Auras
84 {
85 get {return m_NewlyCreatedEntityAura; }
86 }
87
88 public Hashtable Entities
89 {
90 get { return m_CMEntityHash; }
91 }
92
93 #endregion Public Properties
94
95 #region Public Methods
96
97 public bool AddAura(ContentManagementEntity aura)
98 {
99 if (m_NewlyCreatedEntityAura.ContainsKey(aura.UUID))
100 return false;
101 m_NewlyCreatedEntityAura.Add(aura.UUID, aura);
102 return true;
103 }
104
105 public bool AddEntity(ContentManagementEntity ent)
106 {
107 if (m_CMEntityHash.ContainsKey(ent.UUID))
108 return false;
109 m_CMEntityHash.Add(ent.UUID, ent);
110 return true;
111 }
112
113 // Check if there are SceneObjectGroups in the list that do not have corresponding ContentManagementGroups in the CMEntityHash
114 public System.Collections.ArrayList CheckForMissingEntities(System.Collections.Generic.List<EntityBase> currList)
115 {
116 System.Collections.ArrayList missingList = new System.Collections.ArrayList();
117 SceneObjectGroup temp = null;
118 foreach (EntityBase currObj in currList)
119 {
120 if (!(currObj is SceneObjectGroup))
121 continue;
122 temp = (SceneObjectGroup) currObj;
123
124 if (m_CMEntityHash.ContainsKey(temp.UUID))
125 {
126 foreach (SceneObjectPart part in temp.Children.Values)
127 if (!((ContentManagementEntity)m_CMEntityHash[temp.UUID]).HasChildPrim(part.UUID))
128 missingList.Add(part);
129 }
130 else //Entire group is missing from revision. (and is a new part in region)
131 {
132 foreach (SceneObjectPart part in temp.Children.Values)
133 missingList.Add(part);
134 }
135 }
136 return missingList;
137 }
138
139 public void ClearAll()
140 {
141 m_CMEntityHash.Clear();
142 m_NewlyCreatedEntityAura.Clear();
143 }
144
145 // Old uuid and new sceneobjectgroup
146 public AuraMetaEntity CreateAuraForNewlyCreatedEntity(SceneObjectPart part)
147 {
148 AuraMetaEntity ent = new AuraMetaEntity(part.ParentGroup.Scene,
149 part.GetWorldPosition(),
150 MetaEntity.TRANSLUCENT,
151 new Vector3(0,254,0),
152 part.Scale
153 );
154 m_NewlyCreatedEntityAura.Add(part.UUID, ent);
155 return ent;
156 }
157
158 // Old uuid and new sceneobjectgroup
159 public ContentManagementEntity CreateNewEntity(SceneObjectGroup group)
160 {
161 ContentManagementEntity ent = new ContentManagementEntity(group, false);
162 m_CMEntityHash.Add(group.UUID, ent);
163 return ent;
164 }
165
166 public ContentManagementEntity CreateNewEntity(String xml, Scene scene)
167 {
168 ContentManagementEntity ent = new ContentManagementEntity(xml, scene, false);
169 if (ent == null)
170 return null;
171 m_CMEntityHash.Add(ent.UnchangedEntity.UUID, ent);
172 return ent;
173 }
174
175 public bool RemoveEntity(UUID uuid)
176 {
177 if (!m_CMEntityHash.ContainsKey(uuid))
178 return false;
179 m_CMEntityHash.Remove(uuid);
180 return true;
181 }
182
183 public bool RemoveNewlyCreatedEntityAura(UUID uuid)
184 {
185 if (!m_NewlyCreatedEntityAura.ContainsKey(uuid))
186 return false;
187 m_NewlyCreatedEntityAura.Remove(uuid);
188 return true;
189 }
190
191 #endregion Public Methods
192 }
193}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs
new file mode 100644
index 0000000..761dca9
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs
@@ -0,0 +1,362 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// CMModel.cs
31// User: bongiojp
32//
33//
34
35#endregion Header
36
37using System;
38using System.Collections;
39using System.Collections.Generic;
40using System.Diagnostics;
41
42using OpenMetaverse;
43
44using OpenSim;
45using OpenSim.Framework;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Physics.Manager;
49
50using log4net;
51
52namespace OpenSim.Region.OptionalModules.ContentManagement
53{
54 public class CMModel
55 {
56 #region Static Fields
57
58 static float TimeToUpdate = 0;
59 static float TimeToConvertXml = 0;
60 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
61
62 #endregion Static Fields
63
64 #region Fields
65
66 /// <value>
67 /// The class that contains all auras and metaentities used in the CMS.
68 /// </value>
69 CMEntityCollection m_MetaEntityCollection = new CMEntityCollection();
70 IContentDatabase m_database = null;
71
72 #endregion Fields
73
74 #region Constructors
75
76 public CMModel()
77 {
78 }
79
80 #endregion Constructors
81
82 #region Public Properties
83
84 public CMEntityCollection MetaEntityCollection
85 {
86 get { return m_MetaEntityCollection; }
87 }
88
89 #endregion Public Properties
90
91 #region Public Methods
92
93 /// <summary>
94 /// Compares the scene's object group list to the list of meta entities. If there is an object group that does not have a corresponding meta entity
95 /// it is a new part that must have a green aura (for diff mode).
96 /// Returns list of ContentManagementEntities
97 /// </summary>
98 public ArrayList CheckForNewEntitiesMissingAuras(Scene scene)
99 {
100 ArrayList missingList = null;
101 ArrayList newList = new ArrayList();
102
103 m_log.Debug("[CONTENT MANAGEMENT] Checking for new scene object parts in scene: " + scene.RegionInfo.RegionName);
104
105 //Check if the current scene has groups not included in the current list of MetaEntities
106 //If so, then the current scene's parts that are new should be marked green.
107 missingList = m_MetaEntityCollection.CheckForMissingEntities(scene.GetEntities());
108
109 foreach (Object missingPart in missingList)
110 {
111 if (m_MetaEntityCollection.Auras.ContainsKey(((SceneObjectPart)missingPart).UUID))
112 continue;
113 newList.Add(m_MetaEntityCollection.CreateAuraForNewlyCreatedEntity((SceneObjectPart)missingPart));
114 }
115 m_log.Info("Number of missing objects found: " + newList.Count);
116 return newList;
117 }
118
119 /// <summary>
120 /// Uses the database to serialize all current scene objects into xml and save into a database with an accompanying log message.
121 /// </summary>
122 public void CommitRegion(Scene scene, String logMessage)
123 {
124 m_log.Debug("[CONTENT MANAG] saving " + scene.RegionInfo.RegionName + " with log message: " + logMessage + " length of message: " + logMessage.Length);
125 m_database.SaveRegion(scene.RegionInfo.RegionID, scene.RegionInfo.RegionName, logMessage);
126 m_log.Debug("[CONTENT MANAG] the region name we are dealing with heeeeeeeere: " + scene.RegionInfo.RegionName );
127 }
128
129 public void DeleteAllMetaObjects()
130 {
131 m_MetaEntityCollection.ClearAll();
132 }
133
134 public ContentManagementEntity FindMetaEntityAffectedByUndo(UUID uuid)
135 {
136 ContentManagementEntity ent = GetMetaGroupByPrim(uuid);
137 return ent;
138 }
139
140 //-------------------------------- HELPERS --------------------------------------------------------------------//
141 public ContentManagementEntity GetMetaGroupByPrim(UUID uuid)
142 {
143 foreach (Object ent in m_MetaEntityCollection.Entities.Values)
144 {
145 if (((ContentManagementEntity)ent).HasChildPrim(uuid))
146 return (ContentManagementEntity)ent;
147 }
148 return null;
149 }
150
151 public void Initialise(string database)
152 {
153 if (database == "FileSystemDatabase")
154 m_database = new FileSystemDatabase();
155 else if (database == "GitDatabase")
156 m_database = new GitDatabase();
157 }
158
159 public void InitialiseDatabase(Scene scene, string dir)
160 {
161 m_database.Initialise(scene, dir);
162 }
163
164 /// <summary>
165 /// Should be called just once to finish initializing the database.
166 /// </summary>
167 public void PostInitialise()
168 {
169 m_database.PostInitialise();
170 }
171
172 /// <summary>
173 /// Removes the green aura when an a new scene object group is deleted.
174 /// </summary>
175 public void RemoveOrUpdateDeletedEntity(SceneObjectGroup group)
176 {
177 // Deal with new parts not revisioned that have been deleted.
178 foreach (SceneObjectPart part in group.Children.Values)
179 if (m_MetaEntityCollection.Auras.ContainsKey(part.UUID))
180 m_MetaEntityCollection.RemoveNewlyCreatedEntityAura(part.UUID);
181 }
182
183 /// <summary>
184 /// Retrieves the latest revision of a region in xml form,
185 /// converts it to scene object groups and scene presences,
186 /// swaps the current scene's entity list with the revision's list.
187 /// Note: Since deleted objects while
188 /// </summary>
189 public void RollbackRegion(Scene scene)
190 {
191 System.Collections.ArrayList xmllist = null;
192 SceneObjectGroup temp = null;
193 System.Collections.Hashtable deleteListUUIDs = new Hashtable();
194// Dictionary<LLUUID, EntityBase> SearchList = new Dictionary<LLUUID,EntityBase>();
195 Dictionary<UUID, EntityBase> ReplacementList = new Dictionary<UUID,EntityBase>();
196 int revision = m_database.GetMostRecentRevision(scene.RegionInfo.RegionID);
197// EntityBase[] searchArray;
198
199 xmllist = m_database.GetRegionObjectXMLList(scene.RegionInfo.RegionID, revision);
200 if (xmllist == null)
201 {
202 m_log.Info("[CMMODEL]: Region (" + scene.RegionInfo.RegionID + ") does not have given revision number (" + revision + ").");
203 return;
204 }
205
206 m_log.Info("[CMMODEL]: Region (" + scene.RegionInfo.RegionID + ") revision number (" + revision + ").");
207 m_log.Info("[CMMODEL]: Scene Objects = " + xmllist.Count);
208 m_log.Info("[CMMODEL]: Converting scene entities list to specified revision.");
209
210 m_log.ErrorFormat("[CMMODEL]: 1");
211
212 foreach (string xml in xmllist)
213 {
214 try{
215 temp = new SceneObjectGroup(xml);
216 temp.SetScene(scene);
217 foreach (SceneObjectPart part in temp.Children.Values)
218 part.RegionHandle = scene.RegionInfo.RegionHandle;
219 ReplacementList.Add(temp.UUID, (EntityBase)temp);
220 }
221 catch(Exception e)
222 {
223 m_log.Info("[CMMODEL]: Error while creating replacement list for rollback: " + e);
224 }
225 }
226
227 //If in scene but not in revision and not a client, remove them
228 while (true)
229 {
230 try
231 {
232 foreach (EntityBase entity in scene.GetEntities())
233 {
234 if (entity == null)
235 continue;
236
237 if (entity is ScenePresence)
238 {
239 ReplacementList.Add(entity.UUID, entity);
240 continue;
241 }
242 else //if (!ReplacementList.ContainsKey(entity.UUID))
243 deleteListUUIDs.Add(entity.UUID, 0);
244 }
245 }
246 catch(Exception e)
247 {
248 m_log.ErrorFormat("[CMMODEL]: " + e);
249 deleteListUUIDs.Clear();
250 ReplacementList.Clear();
251 continue;
252 }
253 break;
254 }
255
256 foreach (UUID uuid in deleteListUUIDs.Keys)
257 {
258 try
259 {
260 // I thought that the DeleteGroup() function would handle all of this, but it doesn't. I'm not sure WHAT it handles.
261 ((SceneObjectGroup)scene.Entities[uuid]).DetachFromBackup();
262 scene.PhysicsScene.RemovePrim(((SceneObjectGroup)scene.Entities[uuid]).RootPart.PhysActor);
263 scene.SendKillObject(scene.Entities[uuid].LocalId);
264 scene.m_sceneGraph.DeleteSceneObject(uuid, false);
265 ((SceneObjectGroup)scene.Entities[uuid]).DeleteGroup(false);
266 }
267 catch(Exception e)
268 {
269 m_log.ErrorFormat("[CMMODEL]: Error while removing objects from scene: " + e);
270 }
271 }
272
273 lock (scene)
274 {
275 scene.Entities.Clear();
276
277 foreach (KeyValuePair<UUID,EntityBase> kvp in ReplacementList)
278 {
279 scene.Entities.Add(kvp.Value);
280 }
281 }
282
283 foreach (EntityBase ent in ReplacementList.Values)
284 {
285 try
286 {
287 if (!(ent is SceneObjectGroup))
288 continue;
289
290 if ((((SceneObjectGroup)ent).RootPart.GetEffectiveObjectFlags() & (uint) PrimFlags.Phantom) == 0)
291 ((SceneObjectGroup)ent).ApplyPhysics(true);
292 ((SceneObjectGroup)ent).AttachToBackup();
293 ((SceneObjectGroup)ent).HasGroupChanged = true; // If not true, then attaching to backup does nothing because no change is detected.
294 ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate();
295 }
296 catch(Exception e)
297 {
298 m_log.ErrorFormat("[CMMODEL]: Error while attaching new scene entities to backup and scheduling for a full update: " + e);
299 }
300 }
301 m_log.Info("[CMMODEL]: Scheduling a backup of new scene object groups to backup.");
302 scene.Backup();
303 }
304
305 /// <summary>
306 /// Downloads the latest revision of the given scene and converts the xml file to CMEntities. After this method, the view can find the differences
307 /// and display the differences to clients.
308 /// </summary>
309 public void UpdateCMEntities(Scene scene)
310 {
311 Stopwatch x = new Stopwatch();
312 x.Start();
313
314 System.Collections.ArrayList xmllist = null;
315 m_log.Debug("[CONTENT MANAGEMENT] Retrieving object xml files for region: " + scene.RegionInfo.RegionID);
316 xmllist = m_database.GetRegionObjectXMLList(scene.RegionInfo.RegionID);
317 m_log.Info("[FSDB]: got list");
318 if (xmllist == null)
319 return;
320
321 Stopwatch y = new Stopwatch();
322 y.Start();
323 foreach (string xml in xmllist)
324 m_MetaEntityCollection.CreateNewEntity(xml, scene);
325 y.Stop();
326 TimeToConvertXml += y.ElapsedMilliseconds;
327 m_log.Info("[FileSystemDatabase] Time spent converting xml to metaentities for " + scene.RegionInfo.RegionName + ": " + y.ElapsedMilliseconds);
328 m_log.Info("[FileSystemDatabase] Time spent converting xml to metaentities so far: " + TimeToConvertXml);
329
330 m_log.Info("[FSDB]: checking for new scene object parts missing green auras and create the auras");
331 CheckForNewEntitiesMissingAuras(scene);
332
333 x.Stop();
334 TimeToUpdate += x.ElapsedMilliseconds;
335 m_log.Info("[FileSystemDatabase] Time spent Updating entity list for " + scene.RegionInfo.RegionName + ": " + x.ElapsedMilliseconds);
336 m_log.Info("[FileSystemDatabase] Time spent Updating so far: " + TimeToUpdate);
337 }
338
339 /// <summary>
340 /// Detects if a scene object group from the scene list has moved or changed scale. The green aura
341 /// that surrounds the object is then moved or scaled with the group.
342 /// </summary>
343 public System.Collections.ArrayList UpdateNormalEntityEffects(SceneObjectGroup group)
344 {
345 System.Collections.ArrayList auraList = new System.Collections.ArrayList();
346 if (group == null)
347 return null;
348 foreach (SceneObjectPart part in group.Children.Values)
349 {
350 if (m_MetaEntityCollection.Auras.ContainsKey(part.UUID))
351 {
352 ((AuraMetaEntity)m_MetaEntityCollection.Auras[part.UUID]).SetAura(new Vector3(0,254,0), part.Scale);
353 ((AuraMetaEntity)m_MetaEntityCollection.Auras[part.UUID]).RootPart.GroupPosition = part.GetWorldPosition();
354 auraList.Add((AuraMetaEntity)m_MetaEntityCollection.Auras[part.UUID]);
355 }
356 }
357 return auraList;
358 }
359
360 #endregion Public Methods
361 }
362}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMView.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMView.cs
new file mode 100644
index 0000000..a1a4d94
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMView.cs
@@ -0,0 +1,206 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// CMView.cs created with MonoDevelop
31// User: bongiojp at 11:57 AM 7/3/2008
32//
33// To change standard headers go to Edit->Preferences->Coding->Standard Headers
34//
35
36#endregion Header
37
38using System;
39using System.Collections;
40using System.Collections.Generic;
41
42using OpenMetaverse;
43
44using OpenSim;
45using OpenSim.Framework;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Physics.Manager;
49
50using log4net;
51
52namespace OpenSim.Region.OptionalModules.ContentManagement
53{
54 public class CMView
55 {
56 #region Static Fields
57
58 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
59
60 #endregion Static Fields
61
62 #region Fields
63
64 CMModel m_model = null;
65
66 #endregion Fields
67
68 #region Constructors
69
70 public CMView()
71 {
72 }
73
74 #endregion Constructors
75
76 #region Public Methods
77
78 // Auras To
79 public void DisplayAuras(CMEntityCollection auraCollection)
80 {
81 foreach (Object ent in auraCollection.Auras.Values)
82 ((AuraMetaEntity)ent).SendFullUpdateToAll();
83 }
84
85 // Auras To Client
86 public void DisplayAuras(CMEntityCollection auraCollection, IClientAPI client)
87 {
88 foreach (Object ent in auraCollection.Auras.Values)
89 ((AuraMetaEntity)ent).SendFullUpdate(client);
90 }
91
92 // Auras from List To ALL
93 public void DisplayAuras(ArrayList list)
94 {
95 foreach (Object ent in list)
96 {
97 m_log.Debug("[CONTENT MANAGEMENT] displaying new aura riiiiiiiiiiiight NOW");
98 ((AuraMetaEntity)ent).SendFullUpdateToAll();
99 }
100 }
101
102 // Entities to ALL
103 public void DisplayEntities(CMEntityCollection entityCollection)
104 {
105 foreach (Object ent in entityCollection.Entities.Values)
106 ((ContentManagementEntity)ent).SendFullDiffUpdateToAll();
107 }
108
109 // Entities to Client
110 public void DisplayEntities(CMEntityCollection entityCollection, IClientAPI client)
111 {
112 foreach (Object ent in entityCollection.Entities.Values)
113 ((ContentManagementEntity)ent).SendFullDiffUpdate(client);
114 }
115
116 // Entities from List to ALL
117 public void DisplayEntities(ArrayList list)
118 {
119 foreach (Object ent in list)
120 ((ContentManagementEntity)ent).SendFullDiffUpdateToAll();
121 }
122
123 // Entity to ALL
124 public void DisplayEntity(ContentManagementEntity ent)
125 {
126 ent.SendFullDiffUpdateToAll();
127 }
128
129 public void DisplayHelpMenu(Scene scene)
130 {
131 string menu = "Menu:\n";
132 menu += "commit (ci) - saves current state of the region to a database on the server\n";
133 menu += "diff-mode (dm) - displays those aspects of region that have not been saved but changed since the very last revision. Will dynamically update as you change environment.\n";
134 SendSimChatMessage(scene, menu);
135 }
136
137 public void DisplayMetaEntity(UUID uuid)
138 {
139 ContentManagementEntity group = m_model.GetMetaGroupByPrim(uuid);
140 if (group != null)
141 group.SendFullDiffUpdateToAll();
142 }
143
144 /// <summary>
145 /// update all clients of red/green/blue auras and meta entities that the model knows about.
146 /// </summary>
147 public void DisplayRecentChanges()
148 {
149 m_log.Debug("[CONTENT MANAGEMENT] Sending update to clients for " + m_model.MetaEntityCollection.Entities.Count + " objects.");
150 DisplayEntities(m_model.MetaEntityCollection);
151 DisplayAuras(m_model.MetaEntityCollection);
152 }
153
154 public void Hide(ContentManagementEntity ent)
155 {
156 ent.HideFromAll();
157 }
158
159 public void HideAllAuras()
160 {
161 foreach (Object obj in m_model.MetaEntityCollection.Auras.Values)
162 ((MetaEntity)obj).HideFromAll();
163 }
164
165 public void HideAllMetaEntities()
166 {
167 foreach (Object obj in m_model.MetaEntityCollection.Entities.Values)
168 ((ContentManagementEntity)obj).HideFromAll();
169 }
170
171 public void Initialise(CMModel model)
172 {
173 m_model = model;
174 }
175
176 /// <summary>
177 /// Figures out if the part deleted was a new scene object part or a revisioned part that's been deleted.
178 /// If it's a new scene object, any green aura attached to it is deleted.
179 /// If a revisioned part is deleted, a new full update is sent to the environment of the meta entity, which will
180 /// figure out that there should be a red aura and not a blue aura/beam.
181 /// </summary>
182 public void RemoveOrUpdateDeletedEntity(SceneObjectGroup group)
183 {
184 // Deal with revisioned parts that have been deleted.
185 if (m_model.MetaEntityCollection.Entities.ContainsKey(group.UUID))
186 ((ContentManagementEntity)m_model.MetaEntityCollection.Entities[group.UUID]).SendFullDiffUpdateToAll();
187
188 // Deal with new parts not revisioned that have been deleted.
189 foreach (SceneObjectPart part in group.Children.Values)
190 if (m_model.MetaEntityCollection.Auras.ContainsKey(part.UUID))
191 ((AuraMetaEntity)m_model.MetaEntityCollection.Auras[part.UUID]).HideFromAll();
192 }
193
194 public void SendMetaEntitiesToNewClient(IClientAPI client)
195 {
196 }
197
198 public void SendSimChatMessage(Scene scene, string message)
199 {
200 scene.SimChat(Utils.StringToBytes(message),
201 ChatTypeEnum.Broadcast, 0, new Vector3(0,0,0), "Content Manager", UUID.Zero, false);
202 }
203
204 #endregion Public Methods
205 }
206}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/ContentManagementEntity.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/ContentManagementEntity.cs
new file mode 100644
index 0000000..4d65038
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/ContentManagementEntity.cs
@@ -0,0 +1,383 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// ContentManagementEntity.cs
31// User: bongiojp
32//
33//
34
35#endregion Header
36
37using System;
38using System.Collections.Generic;
39using System.Drawing;
40
41using OpenMetaverse;
42
43using Nini.Config;
44
45using OpenSim.Framework;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Physics.Manager;
49
50using log4net;
51
52namespace OpenSim.Region.OptionalModules.ContentManagement
53{
54 public class ContentManagementEntity : MetaEntity
55 {
56 #region Static Fields
57
58// static float TimeToDiff = 0;
59// static float TimeToCreateEntities = 0;
60
61 #endregion Static Fields
62
63 #region Fields
64
65 protected Dictionary<UUID, AuraMetaEntity> m_AuraEntities = new Dictionary<UUID, AuraMetaEntity>();
66 protected Dictionary<UUID, BeamMetaEntity> m_BeamEntities = new Dictionary<UUID, BeamMetaEntity>();
67
68 // The LinkNum of parts in m_Entity and m_UnchangedEntity are the same though UUID and LocalId are different.
69 // This can come in handy.
70 protected SceneObjectGroup m_UnchangedEntity = null;
71
72 /// <value>
73 /// Should be set to true when there is a difference between m_UnchangedEntity and the corresponding scene object group in the scene entity list.
74 /// </value>
75 bool DiffersFromSceneGroup = false;
76
77 #endregion Fields
78
79 #region Constructors
80
81 public ContentManagementEntity(SceneObjectGroup Unchanged, bool physics)
82 : base(Unchanged, false)
83 {
84 m_UnchangedEntity = Unchanged.Copy(Unchanged.RootPart.OwnerID, Unchanged.RootPart.GroupID, false);
85 }
86
87 public ContentManagementEntity(string objectXML, Scene scene, bool physics)
88 : base(objectXML, scene, false)
89 {
90 m_UnchangedEntity = new SceneObjectGroup(objectXML);
91 }
92
93 #endregion Constructors
94
95 #region Public Properties
96
97 public SceneObjectGroup UnchangedEntity
98 {
99 get { return m_UnchangedEntity; }
100 }
101
102 #endregion Public Properties
103
104 #region Private Methods
105
106 /// <summary>
107 /// Check if an entitybase list (like that returned by scene.GetEntities()) contains a group with the rootpart uuid that matches the current uuid.
108 /// </summary>
109 private bool ContainsKey(List<EntityBase> list, UUID uuid)
110 {
111 foreach (EntityBase part in list)
112 if (part.UUID == uuid)
113 return true;
114 return false;
115 }
116
117 private SceneObjectGroup GetGroupByUUID(System.Collections.Generic.List<EntityBase> list, UUID uuid)
118 {
119 foreach (EntityBase ent in list)
120 {
121 if (ent is SceneObjectGroup)
122 if (ent.UUID == uuid)
123 return (SceneObjectGroup)ent;
124 }
125 return null;
126 }
127
128 #endregion Private Methods
129
130 #region Public Methods
131
132 /// <summary>
133 /// Search for a corresponding group UUID in the scene. If not found, then the revisioned group this CMEntity represents has been deleted. Mark the metaentity appropriately.
134 /// If a matching UUID is found in a scene object group, compare the two for differences. If differences exist, Mark the metaentity appropriately.
135 /// </summary>
136 public void FindDifferences()
137 {
138 System.Collections.Generic.List<EntityBase> sceneEntityList = m_Entity.Scene.GetEntities();
139 DiffersFromSceneGroup = false;
140 // if group is not contained in scene's list
141 if (!ContainsKey(sceneEntityList, m_UnchangedEntity.UUID))
142 {
143 foreach (SceneObjectPart part in m_UnchangedEntity.Children.Values)
144 {
145 // if scene list no longer contains this part, display translucent part and mark with red aura
146 if (!ContainsKey(sceneEntityList, part.UUID))
147 {
148 // if already displaying a red aura over part, make sure its red
149 if (m_AuraEntities.ContainsKey(part.UUID))
150 {
151 m_AuraEntities[part.UUID].SetAura(new Vector3(254,0,0), part.Scale);
152 }
153 else
154 {
155 AuraMetaEntity auraGroup = new AuraMetaEntity(m_Entity.Scene,
156 part.GetWorldPosition(),
157 MetaEntity.TRANSLUCENT,
158 new Vector3(254,0,0),
159 part.Scale
160 );
161 m_AuraEntities.Add(part.UUID, auraGroup);
162 }
163 SceneObjectPart metaPart = m_Entity.GetLinkNumPart(part.LinkNum);
164 SetPartTransparency(metaPart, MetaEntity.TRANSLUCENT);
165 }
166 // otherwise, scene will not contain the part. note: a group can not remove a part without changing group id
167 }
168
169 // a deleted part has no where to point a beam particle system,
170 // if a metapart had a particle system (maybe it represented a moved part) remove it
171 if (m_BeamEntities.ContainsKey(m_UnchangedEntity.RootPart.UUID))
172 {
173 m_BeamEntities[m_UnchangedEntity.RootPart.UUID].HideFromAll();
174 m_BeamEntities.Remove(m_UnchangedEntity.RootPart.UUID);
175 }
176
177 DiffersFromSceneGroup = true;
178 }
179 // if scene list does contain group, compare each part in group for differences and display beams and auras appropriately
180 else
181 {
182 MarkWithDifferences((SceneObjectGroup)GetGroupByUUID(sceneEntityList, m_UnchangedEntity.UUID));
183 }
184 }
185
186 /// <summary>
187 /// Check if the revisioned scene object group that this CMEntity is based off of contains a child with the given UUID.
188 /// </summary>
189 public bool HasChildPrim(UUID uuid)
190 {
191 if (m_UnchangedEntity.Children.ContainsKey(uuid))
192 return true;
193 return false;
194 }
195
196 /// <summary>
197 /// Check if the revisioned scene object group that this CMEntity is based off of contains a child with the given LocalId.
198 /// </summary>
199 public bool HasChildPrim(uint localID)
200 {
201 foreach (SceneObjectPart part in m_UnchangedEntity.Children.Values)
202 if (part.LocalId == localID)
203 return true;
204 return false;
205 }
206
207 public override void Hide(IClientAPI client)
208 {
209 base.Hide(client);
210 foreach (MetaEntity group in m_AuraEntities.Values)
211 group.Hide(client);
212 foreach (MetaEntity group in m_BeamEntities.Values)
213 group.Hide(client);
214 }
215
216 public override void HideFromAll()
217 {
218 base.HideFromAll();
219 foreach (MetaEntity group in m_AuraEntities.Values)
220 group.HideFromAll();
221 foreach (MetaEntity group in m_BeamEntities.Values)
222 group.HideFromAll();
223 }
224
225 /// <summary>
226 /// Returns true if there was a change between meta entity and the entity group, false otherwise.
227 /// If true is returned, it is assumed the metaentity's appearance has changed to reflect the difference (though clients haven't been updated).
228 /// </summary>
229 public bool MarkWithDifferences(SceneObjectGroup sceneEntityGroup)
230 {
231 SceneObjectPart sceneEntityPart;
232 SceneObjectPart metaEntityPart;
233 Diff differences;
234 bool changed = false;
235
236 // Use "UnchangedEntity" to do comparisons because its text, transparency, and other attributes will be just as the user
237 // had originally saved.
238 // m_Entity will NOT necessarily be the same entity as the user had saved.
239 foreach (SceneObjectPart UnchangedPart in m_UnchangedEntity.Children.Values)
240 {
241 //This is the part that we use to show changes.
242 metaEntityPart = m_Entity.GetLinkNumPart(UnchangedPart.LinkNum);
243 if (sceneEntityGroup.Children.ContainsKey(UnchangedPart.UUID))
244 {
245 sceneEntityPart = sceneEntityGroup.Children[UnchangedPart.UUID];
246 differences = Difference.FindDifferences(UnchangedPart, sceneEntityPart);
247 if (differences != Diff.NONE)
248 metaEntityPart.Text = "CHANGE: " + differences.ToString();
249 if (differences != 0)
250 {
251 // Root Part that has been modified
252 if ((differences&Diff.POSITION) > 0)
253 {
254 // If the position of any part has changed, make sure the RootPart of the
255 // meta entity is pointing with a beam particle system
256 if (m_BeamEntities.ContainsKey(m_UnchangedEntity.RootPart.UUID))
257 {
258 m_BeamEntities[m_UnchangedEntity.RootPart.UUID].HideFromAll();
259 m_BeamEntities.Remove(m_UnchangedEntity.RootPart.UUID);
260 }
261 BeamMetaEntity beamGroup = new BeamMetaEntity(m_Entity.Scene,
262 m_UnchangedEntity.RootPart.GetWorldPosition(),
263 MetaEntity.TRANSLUCENT,
264 sceneEntityPart,
265 new Vector3(0,0,254)
266 );
267 m_BeamEntities.Add(m_UnchangedEntity.RootPart.UUID, beamGroup);
268 }
269
270 if (m_AuraEntities.ContainsKey(UnchangedPart.UUID))
271 {
272 m_AuraEntities[UnchangedPart.UUID].HideFromAll();
273 m_AuraEntities.Remove(UnchangedPart.UUID);
274 }
275 AuraMetaEntity auraGroup = new AuraMetaEntity(m_Entity.Scene,
276 UnchangedPart.GetWorldPosition(),
277 MetaEntity.TRANSLUCENT,
278 new Vector3(0,0,254),
279 UnchangedPart.Scale
280 );
281 m_AuraEntities.Add(UnchangedPart.UUID, auraGroup);
282 SetPartTransparency(metaEntityPart, MetaEntity.TRANSLUCENT);
283
284 DiffersFromSceneGroup = true;
285 }
286 else // no differences between scene part and meta part
287 {
288 if (m_BeamEntities.ContainsKey(m_UnchangedEntity.RootPart.UUID))
289 {
290 m_BeamEntities[m_UnchangedEntity.RootPart.UUID].HideFromAll();
291 m_BeamEntities.Remove(m_UnchangedEntity.RootPart.UUID);
292 }
293 if (m_AuraEntities.ContainsKey(UnchangedPart.UUID))
294 {
295 m_AuraEntities[UnchangedPart.UUID].HideFromAll();
296 m_AuraEntities.Remove(UnchangedPart.UUID);
297 }
298 SetPartTransparency(metaEntityPart, MetaEntity.NONE);
299 }
300 }
301 else //The entity currently in the scene is missing parts from the metaentity saved, so mark parts red as deleted.
302 {
303 if (m_AuraEntities.ContainsKey(UnchangedPart.UUID))
304 {
305 m_AuraEntities[UnchangedPart.UUID].HideFromAll();
306 m_AuraEntities.Remove(UnchangedPart.UUID);
307 }
308 AuraMetaEntity auraGroup = new AuraMetaEntity(m_Entity.Scene,
309 UnchangedPart.GetWorldPosition(),
310 MetaEntity.TRANSLUCENT,
311 new Vector3(254,0,0),
312 UnchangedPart.Scale
313 );
314 m_AuraEntities.Add(UnchangedPart.UUID, auraGroup);
315 SetPartTransparency(metaEntityPart, MetaEntity.TRANSLUCENT);
316
317 DiffersFromSceneGroup = true;
318 }
319 }
320 return changed;
321 }
322
323 public void SendFullAuraUpdate(IClientAPI client)
324 {
325 if (DiffersFromSceneGroup)
326 {
327 foreach (AuraMetaEntity group in m_AuraEntities.Values)
328 group.SendFullUpdate(client);
329 }
330 }
331
332 public void SendFullAuraUpdateToAll()
333 {
334 if (DiffersFromSceneGroup)
335 {
336 foreach (AuraMetaEntity group in m_AuraEntities.Values)
337 group.SendFullUpdateToAll();
338 }
339 }
340
341 public void SendFullBeamUpdate(IClientAPI client)
342 {
343 if (DiffersFromSceneGroup)
344 {
345 foreach (BeamMetaEntity group in m_BeamEntities.Values)
346 group.SendFullUpdate(client);
347 }
348 }
349
350 public void SendFullBeamUpdateToAll()
351 {
352 if (DiffersFromSceneGroup)
353 {
354 foreach (BeamMetaEntity group in m_BeamEntities.Values)
355 group.SendFullUpdateToAll();
356 }
357 }
358
359 public void SendFullDiffUpdate(IClientAPI client)
360 {
361 FindDifferences();
362 if (DiffersFromSceneGroup)
363 {
364 SendFullUpdate(client);
365 SendFullAuraUpdate(client);
366 SendFullBeamUpdate(client);
367 }
368 }
369
370 public void SendFullDiffUpdateToAll()
371 {
372 FindDifferences();
373 if (DiffersFromSceneGroup)
374 {
375 SendFullUpdateToAll();
376 SendFullAuraUpdateToAll();
377 SendFullBeamUpdateToAll();
378 }
379 }
380
381 #endregion Public Methods
382 }
383}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/ContentManagementModule.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/ContentManagementModule.cs
new file mode 100644
index 0000000..21bc8b2
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/ContentManagementModule.cs
@@ -0,0 +1,163 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// ContentManagementModule.cs
31// User: bongiojp
32
33#endregion Header
34
35using System;
36using System.Collections.Generic;
37using System.Threading;
38
39using OpenMetaverse;
40
41using Nini.Config;
42
43using OpenSim;
44using OpenSim.Framework;
45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.Framework.Scenes;
47using OpenSim.Region.Physics.Manager;
48
49using log4net;
50
51namespace OpenSim.Region.OptionalModules.ContentManagement
52{
53 public class ContentManagementModule : IRegionModule
54 {
55 #region Static Fields
56
57 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
58
59 #endregion Static Fields
60
61 #region Fields
62
63 bool initialised = false;
64 CMController m_control = null;
65 bool m_enabled = false;
66 CMModel m_model = null;
67 bool m_posted = false;
68 CMView m_view = null;
69
70 #endregion Fields
71
72 #region Public Properties
73
74 public bool IsSharedModule
75 {
76 get { return true; }
77 }
78
79 public string Name
80 {
81 get { return "ContentManagementModule"; }
82 }
83
84 #endregion Public Properties
85
86 #region Public Methods
87
88 public void Close()
89 {
90 }
91
92 public void Initialise(Scene scene, IConfigSource source)
93 {
94 string databaseDir = "./";
95 string database = "FileSystemDatabase";
96 int channel = 345;
97 try
98 {
99 if (source.Configs["CMS"] == null)
100 return;
101
102 m_enabled = source.Configs["CMS"].GetBoolean("enabled", false);
103 databaseDir = source.Configs["CMS"].GetString("directory", databaseDir);
104 database = source.Configs["CMS"].GetString("database", database);
105 channel = source.Configs["CMS"].GetInt("channel", channel);
106
107 if (database != "FileSystemDatabase" && database != "GitDatabase")
108 {
109 m_log.ErrorFormat("[Content Management]: The Database attribute must be defined as either FileSystemDatabase or GitDatabase");
110 m_enabled = false;
111 }
112 }
113 catch (Exception e)
114 {
115 m_log.ErrorFormat("[Content Management]: Exception thrown while reading parameters from configuration file. Message: " + e);
116 m_enabled = false;
117 }
118
119 if (!m_enabled)
120 {
121 m_log.Info("[Content Management]: Content Management System is not Enabled.");
122 return;
123 }
124
125 lock (this)
126 {
127 if (!initialised) //only init once
128 {
129 m_view = new CMView();
130 m_model = new CMModel();
131 m_control = new CMController(m_model, m_view, scene, channel);
132 m_model.Initialise(database);
133 m_view.Initialise(m_model);
134
135 initialised = true;
136 m_model.InitialiseDatabase(scene, databaseDir);
137 }
138 else
139 {
140 m_model.InitialiseDatabase(scene, databaseDir);
141 m_control.RegisterNewRegion(scene);
142 }
143 }
144 }
145
146 public void PostInitialise()
147 {
148 if (! m_enabled)
149 return;
150
151 lock (this)
152 {
153 if (!m_posted) //only post once
154 {
155 m_model.PostInitialise();
156 m_posted = true;
157 }
158 }
159 }
160
161 #endregion Public Methods
162 }
163}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/FileSystemDatabase.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/FileSystemDatabase.cs
new file mode 100644
index 0000000..6a50906
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/FileSystemDatabase.cs
@@ -0,0 +1,317 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// FileSystemDatabase.cs
31// User: bongiojp
32
33#endregion Header
34
35using System;
36using System.Collections.Generic;
37using System.Diagnostics;
38using System.IO;
39using Slash = System.IO.Path;
40using System.Reflection;
41using System.Xml;
42
43using OpenMetaverse;
44
45using Nini.Config;
46
47using OpenSim.Framework;
48using OpenSim.Region.Framework.Interfaces;
49using OpenSim.Region.Framework.Scenes;
50using OpenSim.Region.CoreModules.World.Serialiser;
51using OpenSim.Region.CoreModules.World.Terrain;
52using OpenSim.Region.Physics.Manager;
53
54using log4net;
55
56namespace OpenSim.Region.OptionalModules.ContentManagement
57{
58 public class FileSystemDatabase : IContentDatabase
59 {
60 #region Static Fields
61
62 public static float TimeToDownload = 0;
63 public static float TimeToSave = 0;
64 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
65
66 #endregion Static Fields
67
68 #region Fields
69
70 private string m_repodir = null;
71 private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
72 private Dictionary<UUID, IRegionSerialiserModule> m_serialiser = new Dictionary<UUID, IRegionSerialiserModule>();
73
74 #endregion Fields
75
76 #region Constructors
77
78 public FileSystemDatabase()
79 {
80 }
81
82 #endregion Constructors
83
84 #region Private Methods
85
86 // called by postinitialise
87 private void CreateDirectory()
88 {
89 string scenedir;
90 if (!Directory.Exists(m_repodir))
91 Directory.CreateDirectory(m_repodir);
92
93 foreach (UUID region in m_scenes.Keys)
94 {
95 scenedir = m_repodir + Slash.DirectorySeparatorChar + region + Slash.DirectorySeparatorChar;
96 if (!Directory.Exists(scenedir))
97 Directory.CreateDirectory(scenedir);
98 }
99 }
100
101 // called by postinitialise
102 private void SetupSerialiser()
103 {
104 if (m_serialiser.Count == 0)
105 {
106 foreach (UUID region in m_scenes.Keys)
107 {
108 m_serialiser.Add(region, m_scenes[region].RequestModuleInterface<IRegionSerialiserModule>());
109 }
110 }
111 }
112
113 #endregion Private Methods
114
115 #region Public Methods
116
117 public int GetMostRecentRevision(UUID regionid)
118 {
119 return NumOfRegionRev(regionid);
120 }
121
122 public string GetRegionObjectHeightMap(UUID regionid)
123 {
124 String filename = m_repodir + Slash.DirectorySeparatorChar + regionid +
125 Slash.DirectorySeparatorChar + "heightmap.r32";
126 FileStream fs = new FileStream( filename, FileMode.Open);
127 StreamReader sr = new StreamReader(fs);
128 String result = sr.ReadToEnd();
129 sr.Close();
130 fs.Close();
131 return result;
132 }
133
134 public string GetRegionObjectHeightMap(UUID regionid, int revision)
135 {
136 String filename = m_repodir + Slash.DirectorySeparatorChar + regionid +
137 Slash.DirectorySeparatorChar + "heightmap.r32";
138 FileStream fs = new FileStream( filename, FileMode.Open);
139 StreamReader sr = new StreamReader(fs);
140 String result = sr.ReadToEnd();
141 sr.Close();
142 fs.Close();
143 return result;
144 }
145
146 public System.Collections.ArrayList GetRegionObjectXMLList(UUID regionid, int revision)
147 {
148 System.Collections.ArrayList objectList = new System.Collections.ArrayList();
149 string filename = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar +
150 + revision + Slash.DirectorySeparatorChar + "objects.xml";
151 XmlDocument doc = new XmlDocument();
152 XmlNode rootNode;
153 //int primCount = 0;
154 //SceneObjectGroup obj = null;
155
156 if (File.Exists(filename))
157 {
158 XmlTextReader reader = new XmlTextReader(filename);
159 reader.WhitespaceHandling = WhitespaceHandling.None;
160 doc.Load(reader);
161 reader.Close();
162 rootNode = doc.FirstChild;
163 foreach (XmlNode aPrimNode in rootNode.ChildNodes)
164 {
165 objectList.Add(aPrimNode.OuterXml);
166 }
167 return objectList;
168 }
169 return null;
170 }
171
172 public System.Collections.ArrayList GetRegionObjectXMLList(UUID regionid)
173 {
174 int revision = NumOfRegionRev(regionid);
175 m_log.Info("[FSDB]: found revisions:" + revision);
176 System.Collections.ArrayList xmlList = new System.Collections.ArrayList();
177 string filename = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar +
178 + revision + Slash.DirectorySeparatorChar + "objects.xml";
179 XmlDocument doc = new XmlDocument();
180 XmlNode rootNode;
181
182 m_log.Info("[FSDB]: Checking if " + filename + " exists.");
183 if (File.Exists(filename))
184 {
185 Stopwatch x = new Stopwatch();
186 x.Start();
187
188 XmlTextReader reader = new XmlTextReader(filename);
189 reader.WhitespaceHandling = WhitespaceHandling.None;
190 doc.Load(reader);
191 reader.Close();
192 rootNode = doc.FirstChild;
193
194 foreach (XmlNode aPrimNode in rootNode.ChildNodes)
195 {
196 xmlList.Add(aPrimNode.OuterXml);
197 }
198
199 x.Stop();
200 TimeToDownload += x.ElapsedMilliseconds;
201 m_log.Info("[FileSystemDatabase] Time spent retrieving xml files so far: " + TimeToDownload);
202
203 return xmlList;
204 }
205 return null;
206 }
207
208 public void Initialise(Scene scene, string dir)
209 {
210 lock (this)
211 {
212 if (m_repodir == null)
213 m_repodir = dir;
214 }
215 lock (m_scenes)
216 m_scenes.Add(scene.RegionInfo.RegionID, scene);
217 }
218
219 public System.Collections.Generic.SortedDictionary<string, string> ListOfRegionRevisions(UUID regionid)
220 {
221 SortedDictionary<string, string> revisionDict = new SortedDictionary<string,string>();
222
223 string scenedir = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar;
224 string[] directories = Directory.GetDirectories(scenedir);
225
226 FileStream fs = null;
227 StreamReader sr = null;
228 String logMessage = "";
229 String logLocation = "";
230 foreach (string revisionDir in directories)
231 {
232 try
233 {
234 logLocation = revisionDir + Slash.DirectorySeparatorChar + "log";
235 fs = new FileStream( logLocation, FileMode.Open);
236 sr = new StreamReader(fs);
237 logMessage = sr.ReadToEnd();
238 sr.Close();
239 fs.Close();
240 revisionDict.Add(revisionDir, logMessage);
241 }
242 catch (Exception)
243 {
244 }
245 }
246
247 return revisionDict;
248 }
249
250 public int NumOfRegionRev(UUID regionid)
251 {
252 string scenedir = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar;
253 m_log.Info("[FSDB]: Reading scene dir: " + scenedir);
254 string[] directories = Directory.GetDirectories(scenedir);
255 return directories.Length;
256 }
257
258 // Run once and only once.
259 public void PostInitialise()
260 {
261 SetupSerialiser();
262
263 m_log.Info("[FSDB]: Creating repository in " + m_repodir + ".");
264 CreateDirectory();
265 }
266
267 public void SaveRegion(UUID regionid, string regionName, string logMessage)
268 {
269 m_log.Info("[FSDB]: ...............................");
270 string scenedir = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar;
271
272 m_log.Info("[FSDB]: checking if scene directory exists: " + scenedir);
273 if (!Directory.Exists(scenedir))
274 Directory.CreateDirectory(scenedir);
275
276 int newRevisionNum = GetMostRecentRevision(regionid)+1;
277 string revisiondir = scenedir + newRevisionNum + Slash.DirectorySeparatorChar;
278
279 m_log.Info("[FSDB]: checking if revision directory exists: " + revisiondir);
280 if (!Directory.Exists(revisiondir))
281 Directory.CreateDirectory(revisiondir);
282
283 try {
284 Stopwatch x = new Stopwatch();
285 x.Start();
286 if (m_scenes.ContainsKey(regionid))
287 {
288 m_serialiser[regionid].SerialiseRegion(m_scenes[regionid], revisiondir);
289 }
290 x.Stop();
291 TimeToSave += x.ElapsedMilliseconds;
292 m_log.Info("[FileSystemDatabase] Time spent serialising regions to files on disk for " + regionName + ": " + x.ElapsedMilliseconds);
293 m_log.Info("[FileSystemDatabase] Time spent serialising regions to files on disk so far: " + TimeToSave);
294 }
295 catch (Exception e)
296 {
297 m_log.ErrorFormat("[FSDB]: Serialisation of region failed: " + e);
298 return;
299 }
300
301 try {
302 // Finish by writing log message.
303 FileStream file = new FileStream(revisiondir + "log", FileMode.Create, FileAccess.ReadWrite);
304 StreamWriter sw = new StreamWriter(file);
305 sw.Write(logMessage);
306 sw.Close();
307 }
308 catch (Exception e)
309 {
310 m_log.ErrorFormat("[FSDB]: Failed trying to save log file " + e);
311 return;
312 }
313 }
314
315 #endregion Public Methods
316 }
317}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/GitDatabase.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/GitDatabase.cs
new file mode 100644
index 0000000..d24747c
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/GitDatabase.cs
@@ -0,0 +1,167 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// GitDatabase.cs
31//
32//
33//
34
35#endregion Header
36
37using System;
38using System.Collections.Generic;
39using System.IO;
40using Slash = System.IO.Path;
41using System.Reflection;
42using System.Xml;
43
44using OpenMetaverse;
45
46using Nini.Config;
47
48using OpenSim.Framework;
49using OpenSim.Region.Framework.Interfaces;
50using OpenSim.Region.Framework.Scenes;
51using OpenSim.Region.CoreModules.World.Serialiser;
52using OpenSim.Region.CoreModules.World.Terrain;
53using OpenSim.Region.Physics.Manager;
54
55using log4net;
56
57namespace OpenSim.Region.OptionalModules.ContentManagement
58{
59 /// <summary>
60 /// Just a stub :-(
61 /// </summary>
62 public class GitDatabase : IContentDatabase
63 {
64 #region Constructors
65
66 public GitDatabase()
67 {
68 }
69
70 #endregion Constructors
71
72 #region Public Methods
73
74 public SceneObjectGroup GetMostRecentObjectRevision(UUID id)
75 {
76 return null;
77 }
78
79 public int GetMostRecentRevision(UUID regionid)
80 {
81 return 0;
82 }
83
84 public SceneObjectGroup GetObjectRevision(UUID id, int revision)
85 {
86 return null;
87 }
88
89 public System.Collections.ArrayList GetObjectsFromRegion(UUID regionid, int revision)
90 {
91 return null;
92 }
93
94 public string GetRegionObjectHeightMap(UUID regionid)
95 {
96 return null;
97 }
98
99 public string GetRegionObjectHeightMap(UUID regionid, int revision)
100 {
101 return null;
102 }
103
104 public string GetRegionObjectXML(UUID regionid)
105 {
106 return null;
107 }
108
109 public string GetRegionObjectXML(UUID regionid, int revision)
110 {
111 return null;
112 }
113
114 public System.Collections.ArrayList GetRegionObjectXMLList(UUID regionid)
115 {
116 return null;
117 }
118
119 public System.Collections.ArrayList GetRegionObjectXMLList(UUID regionid, int revision)
120 {
121 return null;
122 }
123
124 public bool InRepository(UUID id)
125 {
126 return false;
127 }
128
129 public void Initialise(Scene scene, String dir)
130 {
131 }
132
133 public System.Collections.Generic.SortedDictionary<string, string> ListOfObjectRevisions(UUID id)
134 {
135 return null;
136 }
137
138 public System.Collections.Generic.SortedDictionary<string, string> ListOfRegionRevisions(UUID id)
139 {
140 return null;
141 }
142
143 public int NumOfObjectRev(UUID id)
144 {
145 return 0;
146 }
147
148 public int NumOfRegionRev(UUID regionid)
149 {
150 return 0;
151 }
152
153 public void PostInitialise()
154 {
155 }
156
157 public void SaveObject(SceneObjectGroup entity)
158 {
159 }
160
161 public void SaveRegion(UUID regionid, string regionName, string logMessage)
162 {
163 }
164
165 #endregion Public Methods
166 }
167}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/IContentDatabase.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/IContentDatabase.cs
new file mode 100644
index 0000000..7a25fa5
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/IContentDatabase.cs
@@ -0,0 +1,94 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// IContentDatabase.cs
31// User: bongiojp
32//
33//
34//
35
36#endregion Header
37
38using System;
39using OpenMetaverse;
40using OpenSim.Region.Framework.Scenes;
41using Nini.Config;
42
43namespace OpenSim.Region.OptionalModules.ContentManagement
44{
45 public interface IContentDatabase
46 {
47 #region Methods
48
49 /// <summary>
50 /// Returns the most recent revision number of a region.
51 /// </summary>
52 int GetMostRecentRevision(UUID regionid);
53
54 string GetRegionObjectHeightMap(UUID regionid);
55
56 string GetRegionObjectHeightMap(UUID regionid, int revision);
57
58 /// <summary>
59 /// Retrieves the xml that describes each individual object from the last revision or specific revision of the given region.
60 /// </summary>
61 System.Collections.ArrayList GetRegionObjectXMLList(UUID regionid);
62
63 System.Collections.ArrayList GetRegionObjectXMLList(UUID regionid, int revision);
64
65 /// <summary>
66 /// Similar to the IRegionModule function. This is the function to be called before attempting to interface with the database.
67 /// Initialise should be called one for each region to be contained in the database. The directory should be the full path
68 /// to the repository and will only be defined once, regardless of how many times the method is called.
69 /// </summary>
70 void Initialise(Scene scene, String dir);
71
72 /// <summary>
73 /// Returns a list of the revision numbers and corresponding log messages for a given region.
74 /// </summary>
75 System.Collections.Generic.SortedDictionary<string, string> ListOfRegionRevisions(UUID id);
76
77 /// <summary>
78 /// Returns the total number of revisions saved for a specific region.
79 /// </summary>
80 int NumOfRegionRev(UUID regionid);
81
82 /// <summary>
83 /// Should be called once after Initialise has been called.
84 /// </summary>
85 void PostInitialise();
86
87 /// <summary>
88 /// Saves the Region terrain map and objects within the region as xml to the database.
89 /// </summary>
90 void SaveRegion(UUID regionid, string regionName, string logMessage);
91
92 #endregion Methods
93 }
94}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
new file mode 100644
index 0000000..63c74e1
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
@@ -0,0 +1,274 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// MetaEntity.cs
31// User: bongiojp
32//
33// TODO:
34// Create a physics manager to the meta object if there isn't one or the object knows of no scene but the user wants physics enabled.
35
36#endregion Header
37
38using System;
39using System.Collections.Generic;
40using System.Drawing;
41
42using OpenMetaverse;
43
44using Nini.Config;
45
46using OpenSim.Framework;
47using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Region.Physics.Manager;
50
51using log4net;
52
53namespace OpenSim.Region.OptionalModules.ContentManagement
54{
55 public class MetaEntity
56 {
57 #region Constants
58
59 public const float INVISIBLE = .95f;
60
61 // Settings for transparency of metaentity
62 public const float NONE = 0f;
63 public const float TRANSLUCENT = .5f;
64
65 #endregion Constants
66
67 #region Static Fields
68
69 protected static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
70
71 #endregion Static Fields
72
73 #region Fields
74
75 protected SceneObjectGroup m_Entity = null; // The scene object group that represents this meta entity.
76 protected uint m_metaLocalid;
77
78 #endregion Fields
79
80 #region Constructors
81
82 public MetaEntity()
83 {
84 }
85
86 /// <summary>
87 /// Makes a new meta entity by copying the given scene object group.
88 /// The physics boolean is just a stub right now.
89 /// </summary>
90 public MetaEntity(SceneObjectGroup orig, bool physics)
91 {
92 m_Entity = orig.Copy(orig.RootPart.OwnerID, orig.RootPart.GroupID, false);
93 Initialize(physics);
94 }
95
96 /// <summary>
97 /// Takes an XML description of a scene object group and converts it to a meta entity.
98 /// </summary>
99 public MetaEntity(string objectXML, Scene scene, bool physics)
100 {
101 m_Entity = new SceneObjectGroup(objectXML);
102 m_Entity.SetScene(scene);
103 Initialize(physics);
104 }
105
106 #endregion Constructors
107
108 #region Public Properties
109
110 public Dictionary<UUID, SceneObjectPart> Children
111 {
112 get { return m_Entity.Children; }
113 set { m_Entity.Children = value; }
114 }
115
116 public uint LocalId
117 {
118 get { return m_Entity.LocalId; }
119 set { m_Entity.LocalId = value; }
120 }
121
122 public SceneObjectGroup ObjectGroup
123 {
124 get { return m_Entity; }
125 }
126
127 public int PrimCount
128 {
129 get { return m_Entity.PrimCount; }
130 }
131
132 public SceneObjectPart RootPart
133 {
134 get { return m_Entity.RootPart; }
135 }
136
137 public Scene Scene
138 {
139 get { return m_Entity.Scene; }
140 }
141
142 public UUID UUID
143 {
144 get { return m_Entity.UUID; }
145 set { m_Entity.UUID = value; }
146 }
147
148 #endregion Public Properties
149
150 #region Protected Methods
151
152 // The metaentity objectgroup must have unique localids as well as unique uuids.
153 // localids are used by the client to refer to parts.
154 // uuids are sent to the client and back to the server to identify parts on the server side.
155 /// <summary>
156 /// Changes localids and uuids of m_Entity.
157 /// </summary>
158 protected void Initialize(bool physics)
159 {
160 //make new uuids
161 Dictionary<UUID, SceneObjectPart> parts = new Dictionary<UUID, SceneObjectPart>();
162 foreach (SceneObjectPart part in m_Entity.Children.Values)
163 {
164 part.ResetIDs(part.LinkNum);
165 parts.Add(part.UUID, part);
166 }
167
168 //finalize
169 m_Entity.RootPart.PhysActor = null;
170 m_Entity.Children = parts;
171 }
172
173 #endregion Protected Methods
174
175 #region Public Methods
176
177 /// <summary>
178 /// Hides the metaentity from a single client.
179 /// </summary>
180 public virtual void Hide(IClientAPI client)
181 {
182 //This deletes the group without removing from any databases.
183 //This is important because we are not IN any database.
184 //m_Entity.FakeDeleteGroup();
185 foreach (SceneObjectPart part in m_Entity.Children.Values)
186 client.SendKillObject(m_Entity.RegionHandle, part.LocalId);
187 }
188
189 /// <summary>
190 /// Sends a kill object message to all clients, effectively "hiding" the metaentity even though it's still on the server.
191 /// </summary>
192 public virtual void HideFromAll()
193 {
194 foreach (SceneObjectPart part in m_Entity.Children.Values)
195 m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller)
196 { controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); }
197 );
198 }
199
200 public void SendFullUpdate(IClientAPI client)
201 {
202 // Not sure what clientFlags should be but 0 seems to work
203 SendFullUpdate(client, 0);
204 }
205
206 public void SendFullUpdate(IClientAPI client, uint clientFlags)
207 {
208 m_Entity.SendFullUpdateToClient(client);
209 }
210
211 public void SendFullUpdateToAll()
212 {
213 m_Entity.Scene.ClientManager.ForEachClient(delegate(IClientAPI controller)
214 { m_Entity.SendFullUpdateToClient(controller); }
215 );
216 }
217
218 /// <summary>
219 /// Makes a single SceneObjectPart see through.
220 /// </summary>
221 /// <param name="part">
222 /// A <see cref="SceneObjectPart"/>
223 /// The part to make see through
224 /// </param>
225 /// <param name="transparencyAmount">
226 /// A <see cref="System.Single"/>
227 /// The degree of transparency to imbue the part with, 0f being solid and .95f being invisible.
228 /// </param>
229 public static void SetPartTransparency(SceneObjectPart part, float transparencyAmount)
230 {
231 Primitive.TextureEntry tex = null;
232 Color4 texcolor;
233 try
234 {
235 tex = part.Shape.Textures;
236 texcolor = new Color4();
237 }
238 catch(Exception)
239 {
240 //m_log.ErrorFormat("[Content Management]: Exception thrown while accessing textures of scene object: " + e);
241 return;
242 }
243
244 for (uint i = 0; i < tex.FaceTextures.Length; i++)
245 {
246 try {
247 if (tex.FaceTextures[i] != null)
248 {
249 texcolor = tex.FaceTextures[i].RGBA;
250 texcolor.A = transparencyAmount;
251 tex.FaceTextures[i].RGBA = texcolor;
252 }
253 }
254 catch (Exception)
255 {
256 //m_log.ErrorFormat("[Content Management]: Exception thrown while accessing different face textures of object: " + e);
257 continue;
258 }
259 }
260 try {
261 texcolor = tex.DefaultTexture.RGBA;
262 texcolor.A = transparencyAmount;
263 tex.DefaultTexture.RGBA = texcolor;
264 part.Shape.TextureEntry = tex.ToBytes();
265 }
266 catch (Exception)
267 {
268 //m_log.Info("[Content Management]: Exception thrown while accessing default face texture of object: " + e);
269 }
270 }
271
272 #endregion Public Methods
273 }
274}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/PointMetaEntity.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/PointMetaEntity.cs
new file mode 100644
index 0000000..22f09fd
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/PointMetaEntity.cs
@@ -0,0 +1,116 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// PointMetaEntity.cs created with MonoDevelop
31// User: bongiojp at 3:03 PM 8/6/2008
32//
33// To change standard headers go to Edit->Preferences->Coding->Standard Headers
34//
35
36#endregion Header
37
38using System;
39using System.Collections.Generic;
40using System.Drawing;
41
42using OpenMetaverse;
43
44using Nini.Config;
45
46using OpenSim.Framework;
47using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Region.Physics.Manager;
50
51using log4net;
52
53namespace OpenSim.Region.OptionalModules.ContentManagement
54{
55 public class PointMetaEntity : MetaEntity
56 {
57 #region Constructors
58
59 public PointMetaEntity(Scene scene, Vector3 groupPos, float transparency)
60 : base()
61 {
62 CreatePointEntity(scene, UUID.Random(), groupPos);
63 SetPartTransparency(m_Entity.RootPart, transparency);
64 }
65
66 public PointMetaEntity(Scene scene, UUID uuid, Vector3 groupPos, float transparency)
67 : base()
68 {
69 CreatePointEntity(scene, uuid, groupPos);
70 SetPartTransparency(m_Entity.RootPart, transparency);
71 }
72
73 #endregion Constructors
74
75 #region Private Methods
76
77 private void CreatePointEntity(Scene scene, UUID uuid, Vector3 groupPos)
78 {
79 SceneObjectGroup x = new SceneObjectGroup();
80 SceneObjectPart y = new SceneObjectPart();
81
82 //Initialize part
83 y.Name = "Very Small Point";
84 y.RegionHandle = scene.RegionInfo.RegionHandle;
85 y.CreationDate = (Int32) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
86 y.OwnerID = UUID.Zero;
87 y.CreatorID = UUID.Zero;
88 y.LastOwnerID = UUID.Zero;
89 y.UUID = uuid;
90
91 y.Shape = PrimitiveBaseShape.CreateBox();
92 y.Scale = new Vector3(0.01f,0.01f,0.01f);
93 y.LastOwnerID = UUID.Zero;
94 y.GroupPosition = groupPos;
95 y.OffsetPosition = new Vector3(0, 0, 0);
96 y.RotationOffset = new Quaternion(0,0,0,0);
97 y.Velocity = new Vector3(0, 0, 0);
98 y.RotationalVelocity = new Vector3(0, 0, 0);
99 y.AngularVelocity = new Vector3(0, 0, 0);
100 y.Acceleration = new Vector3(0, 0, 0);
101
102 y.Flags = 0;
103 y.TrimPermissions();
104
105 //Initialize group and add part as root part
106 x.SetScene(scene);
107 x.SetRootPart(y);
108 x.RegionHandle = scene.RegionInfo.RegionHandle;
109 x.SetScene(scene);
110
111 m_Entity = x;
112 }
113
114 #endregion Private Methods
115 }
116}
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/README b/OpenSim/Region/OptionalModules/ContentManagementSystem/README
new file mode 100644
index 0000000..1a69fef
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/README
@@ -0,0 +1,52 @@
1This module is meant to be built alone and not added to the Opensim code base. References are made to required dlls through a
2reference file, ContentManagement.mdp. Originally, for development, this project was contained in the Opensim/Region/Modules/
3directory.
4
5To compile: nant
6To use: Copy ContentManagement.dll into the bin directory of your Opensim build. You should find many other dlls in the same directory.
7
8
9--------------------------------------------------------------------------------------------------------------------
10To build the libgit.so file:
11
12#Download GIT git repository
13$ git clone git://git2.kernel.org/pub/OpenSim/Region/Environment/Modules/ContentManagementSystem/scm/git/git.git
14$ cd git
15
16#Compile GIT
17#Note that we are adding two extra flags to pass to gcc while compiling (-c and -fPIC)
18$ autoconf
19$ ./configure
20$ CFLAGS="-g -O2 -Wall -c -fPIC" make
21
22#Copy necessary object files (and some not so necessary) to their own directory for shared object file creation
23$ mkdir ../libgit-objects
24$ cp builtin*.o ../libgit-objects
25$ cp xdiff/*.o ../libgit-objects
26$ cp libgit.a ../libgit-objects
27
28#Remove the main symbol from any object files (like git.o)
29$ cd ../libgit-objects
30$ strip -N main *.o
31
32#Uncompress the plumbing objects from archive created by git
33$ ar x libgit.a
34
35#Create shared object file from all objects (including the zlib library)
36$ ld -shared -soname libgit.so.1 -o libgit.so.1.5.6.3 -lc -lz *.o
37
38
39#You can also just copy the following commands into a file and run as a script inside the git directory
40
41make clean
42autoconf
43./configure
44CFLAGS="-g -O2 -Wall -c -fPIC" make
45mkdir libgit-objects
46cp builtin*.o libgit-objects
47cp xdiff/*.o libgit-objects
48cp libgit.a libgit-objects
49cd libgit-objects
50strip -N main *.o
51ar x libgit.a
52ld -shared -soname libgit.so.1 -o libgit.so.1.5.6.3 -lc -lz *.o \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/SceneObjectGroupDiff.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/SceneObjectGroupDiff.cs
new file mode 100644
index 0000000..8957e8f
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/SceneObjectGroupDiff.cs
@@ -0,0 +1,218 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#region Header
29
30// SceneObjectGroupDiff.cs
31// User: bongiojp
32
33#endregion Header
34
35using System;
36using System.Collections.Generic;
37using System.Diagnostics;
38using System.Drawing;
39
40using OpenMetaverse;
41
42using Nini.Config;
43
44using OpenSim.Framework;
45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.Framework.Scenes;
47using OpenSim.Region.Physics.Manager;
48
49using log4net;
50
51namespace OpenSim.Region.OptionalModules.ContentManagement
52{
53 #region Enumerations
54
55 [Flags]
56 public enum Diff
57 {
58 NONE = 0,
59 FACECOLOR = 1,
60 SHAPE = 1<<1,
61 MATERIAL = 1<<2,
62 TEXTURE = 1<<3,
63 SCALE = 1<<4,
64 POSITION = 1<<5,
65 OFFSETPOSITION = 1<<6,
66 ROTATIONOFFSET = 1<<7,
67 ROTATIONALVELOCITY = 1<<8,
68 ACCELERATION = 1<<9,
69 ANGULARVELOCITY = 1<<10,
70 VELOCITY = 1<<11,
71 OBJECTOWNER = 1<<12,
72 PERMISSIONS = 1<<13,
73 DESCRIPTION = 1<<14,
74 NAME = 1<<15,
75 SCRIPT = 1<<16,
76 CLICKACTION = 1<<17,
77 PARTICLESYSTEM = 1<<18,
78 GLOW = 1<<19,
79 SALEPRICE = 1<<20,
80 SITNAME = 1<<21,
81 SITTARGETORIENTATION = 1<<22,
82 SITTARGETPOSITION = 1<<23,
83 TEXT = 1<<24,
84 TOUCHNAME = 1<<25
85 }
86
87 #endregion Enumerations
88
89 public static class Difference
90 {
91 #region Static Fields
92
93 static float TimeToDiff = 0;
94// private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
95
96 #endregion Static Fields
97
98 #region Private Methods
99
100 private static bool AreQuaternionsEquivalent(Quaternion first, Quaternion second)
101 {
102 Vector3 firstVector = llRot2Euler(first);
103 Vector3 secondVector = llRot2Euler(second);
104 return AreVectorsEquivalent(firstVector, secondVector);
105 }
106
107 private static bool AreVectorsEquivalent(Vector3 first, Vector3 second)
108 {
109 if (TruncateSignificant(first.X, 2) == TruncateSignificant(second.X, 2)
110 && TruncateSignificant(first.Y, 2) == TruncateSignificant(second.Y, 2)
111 && TruncateSignificant(first.Z, 2) == TruncateSignificant(second.Z, 2)
112 )
113 return true;
114 else
115 return false;
116 }
117
118 // Taken from Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs
119 private static double NormalizeAngle(double angle)
120 {
121 angle = angle % (Math.PI * 2);
122 if (angle < 0) angle = angle + Math.PI * 2;
123 return angle;
124 }
125
126 private static int TruncateSignificant(float num, int digits)
127 {
128 return (int) Math.Ceiling((Math.Truncate(num * 10 * digits)/10*digits));
129 // return (int) ((num * (10*digits))/10*digits);
130 }
131
132 // Taken from Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs
133 // Also changed the original function from LSL_Types to LL types
134 private static Vector3 llRot2Euler(Quaternion r)
135 {
136 Quaternion t = new Quaternion(r.X * r.X, r.Y * r.Y, r.Z * r.Z, r.W * r.W);
137 double m = (t.X + t.Y + t.Z + t.W);
138 if (m == 0) return new Vector3();
139 double n = 2 * (r.Y * r.W + r.X * r.Z);
140 double p = m * m - n * n;
141 if (p > 0)
142 return new Vector3((float)NormalizeAngle(Math.Atan2(2.0 * (r.X * r.W - r.Y * r.Z), (-t.X - t.Y + t.Z + t.W))),
143 (float)NormalizeAngle(Math.Atan2(n, Math.Sqrt(p))),
144 (float)NormalizeAngle(Math.Atan2(2.0 * (r.Z * r.W - r.X * r.Y), (t.X - t.Y - t.Z + t.W))));
145 else if (n > 0)
146 return new Vector3(0.0f, (float)(Math.PI / 2), (float)NormalizeAngle(Math.Atan2((r.Z * r.W + r.X * r.Y), 0.5 - t.X - t.Z)));
147 else
148 return new Vector3(0.0f, (float)(-Math.PI / 2), (float)NormalizeAngle(Math.Atan2((r.Z * r.W + r.X * r.Y), 0.5 - t.X - t.Z)));
149 }
150
151 #endregion Private Methods
152
153 #region Public Methods
154
155 /// <summary>
156 /// Compares the attributes (Vectors, Quaternions, Strings, etc.) between two scene object parts
157 /// and returns a Diff bitmask which details what the differences are.
158 /// </summary>
159 public static Diff FindDifferences(SceneObjectPart first, SceneObjectPart second)
160 {
161 Stopwatch x = new Stopwatch();
162 x.Start();
163
164 Diff result = 0;
165
166 // VECTOR COMPARISONS
167 if (!AreVectorsEquivalent(first.Acceleration, second.Acceleration))
168 result |= Diff.ACCELERATION;
169 if (!AreVectorsEquivalent(first.AbsolutePosition, second.AbsolutePosition))
170 result |= Diff.POSITION;
171 if (!AreVectorsEquivalent(first.AngularVelocity, second.AngularVelocity))
172 result |= Diff.ANGULARVELOCITY;
173 if (!AreVectorsEquivalent(first.OffsetPosition, second.OffsetPosition))
174 result |= Diff.OFFSETPOSITION;
175 if (!AreVectorsEquivalent(first.RotationalVelocity, second.RotationalVelocity))
176 result |= Diff.ROTATIONALVELOCITY;
177 if (!AreVectorsEquivalent(first.Scale, second.Scale))
178 result |= Diff.SCALE;
179 if (!AreVectorsEquivalent(first.Velocity, second.Velocity))
180 result |= Diff.VELOCITY;
181
182
183 // QUATERNION COMPARISONS
184 if (!AreQuaternionsEquivalent(first.RotationOffset, second.RotationOffset))
185 result |= Diff.ROTATIONOFFSET;
186
187
188 // MISC COMPARISONS (UUID, Byte)
189 if (first.ClickAction != second.ClickAction)
190 result |= Diff.CLICKACTION;
191 if (first.ObjectOwner != second.ObjectOwner)
192 result |= Diff.OBJECTOWNER;
193
194
195 // STRING COMPARISONS
196 if (first.Description != second.Description)
197 result |= Diff.DESCRIPTION;
198 if (first.Material != second.Material)
199 result |= Diff.MATERIAL;
200 if (first.Name != second.Name)
201 result |= Diff.NAME;
202 if (first.SitName != second.SitName)
203 result |= Diff.SITNAME;
204 if (first.Text != second.Text)
205 result |= Diff.TEXT;
206 if (first.TouchName != second.TouchName)
207 result |= Diff.TOUCHNAME;
208
209 x.Stop();
210 TimeToDiff += x.ElapsedMilliseconds;
211 //m_log.Info("[DIFFERENCES] Time spent diffing objects so far" + TimeToDiff);
212
213 return result;
214 }
215
216 #endregion Public Methods
217 }
218}
diff --git a/OpenSim/Region/OptionalModules/Grid/Interregion/IInterregionModule.cs b/OpenSim/Region/OptionalModules/Grid/Interregion/IInterregionModule.cs
new file mode 100644
index 0000000..a2c98a4
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Grid/Interregion/IInterregionModule.cs
@@ -0,0 +1,43 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Framework;
29using OpenSim.Region.Framework.Scenes;
30
31namespace OpenSim.Region.CoreModules.Grid.Interregion
32{
33 public interface IInterregionModule
34 {
35 void RegisterMethod<T>(T e);
36 bool HasInterface<T>(Location loc);
37 T RequestInterface<T>(Location loc);
38 T[] RequestInterface<T>();
39 Location GetLocationByDirection(Scene scene, InterregionModule.Direction dir);
40 void internal_CreateRemotingObjects();
41 void RegisterRemoteRegion(string uri);
42 }
43} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Grid/Interregion/InterregionModule.cs b/OpenSim/Region/OptionalModules/Grid/Interregion/InterregionModule.cs
new file mode 100644
index 0000000..21df83c
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Grid/Interregion/InterregionModule.cs
@@ -0,0 +1,199 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Runtime.Remoting;
31using System.Runtime.Remoting.Channels;
32using System.Runtime.Remoting.Channels.Tcp;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37
38namespace OpenSim.Region.CoreModules.Grid.Interregion
39{
40 public class InterregionModule : IInterregionModule, IRegionModule
41 {
42 #region Direction enum
43
44 public enum Direction
45 {
46 North,
47 NorthEast,
48 East,
49 SouthEast,
50 South,
51 SouthWest,
52 West,
53 NorthWest
54 }
55
56 #endregion
57
58 private readonly Dictionary<Type, Object> m_interfaces = new Dictionary<Type, object>();
59 private readonly Object m_lockObject = new object();
60 private readonly List<Location> m_myLocations = new List<Location>();
61
62 private readonly Dictionary<Location, string[]> m_neighbourInterfaces = new Dictionary<Location, string[]>();
63 private readonly Dictionary<Location, RemotingObject> m_neighbourRemote = new Dictionary<Location, RemotingObject>();
64 // private IConfigSource m_config;
65 private const bool m_enabled = false;
66
67 private RemotingObject m_myRemote;
68 private TcpChannel m_tcpChannel;
69 private int m_tcpPort = 10101;
70
71 #region IInterregionModule Members
72
73 public void internal_CreateRemotingObjects()
74 {
75 lock (m_lockObject)
76 {
77 if (m_tcpChannel == null)
78 {
79 m_myRemote = new RemotingObject(m_interfaces, m_myLocations.ToArray());
80 m_tcpChannel = new TcpChannel(m_tcpPort);
81
82 ChannelServices.RegisterChannel(m_tcpChannel, false);
83 RemotingServices.Marshal(m_myRemote, "OpenSimRemote2", typeof (RemotingObject));
84 }
85 }
86 }
87
88 public void RegisterMethod<T>(T e)
89 {
90 m_interfaces[typeof (T)] = e;
91 }
92
93 public bool HasInterface<T>(Location loc)
94 {
95 foreach (string val in m_neighbourInterfaces[loc])
96 {
97 if (val == typeof (T).FullName)
98 {
99 return true;
100 }
101 }
102 return false;
103 }
104
105 public T RequestInterface<T>(Location loc)
106 {
107 if (m_neighbourRemote.ContainsKey(loc))
108 {
109 return m_neighbourRemote[loc].RequestInterface<T>();
110 }
111 throw new IndexOutOfRangeException("No neighbour availible at that location");
112 }
113
114 public T[] RequestInterface<T>()
115 {
116 List<T> m_t = new List<T>();
117 foreach (RemotingObject remote in m_neighbourRemote.Values)
118 {
119 try
120 {
121 m_t.Add(remote.RequestInterface<T>());
122 }
123 catch (NotSupportedException)
124 {
125 }
126 }
127 return m_t.ToArray();
128 }
129
130 public Location GetLocationByDirection(Scene scene, Direction dir)
131 {
132 return new Location(0, 0);
133 }
134
135 public void RegisterRemoteRegion(string uri)
136 {
137 RegisterRemotingInterface((RemotingObject) Activator.GetObject(typeof (RemotingObject), uri));
138 }
139
140 #endregion
141
142 #region IRegionModule Members
143
144 public void Initialise(Scene scene, IConfigSource source)
145 {
146 m_myLocations.Add(new Location((int) scene.RegionInfo.RegionLocX,
147 (int) scene.RegionInfo.RegionLocY));
148 // m_config = source;
149
150 scene.RegisterModuleInterface<IInterregionModule>(this);
151 }
152
153 public void PostInitialise()
154 {
155 // Commenting out to remove 'unreachable code' warning since m_enabled is never true
156// if (m_enabled)
157// {
158// try
159// {
160// m_tcpPort = m_config.Configs["Comms"].GetInt("remoting_port", m_tcpPort);
161// }
162// catch
163// {
164// }
165//
166// internal_CreateRemotingObjects();
167// }
168 }
169
170 public void Close()
171 {
172 if (null != m_tcpChannel)
173 ChannelServices.UnregisterChannel(m_tcpChannel);
174 }
175
176 public string Name
177 {
178 get { return "InterregionModule"; }
179 }
180
181 public bool IsSharedModule
182 {
183 get { return true; }
184 }
185
186 #endregion
187
188 private void RegisterRemotingInterface(RemotingObject remote)
189 {
190 Location[] locs = remote.GetLocations();
191 string[] interfaces = remote.GetInterfaces();
192 foreach (Location loc in locs)
193 {
194 m_neighbourInterfaces[loc] = interfaces;
195 m_neighbourRemote[loc] = remote;
196 }
197 }
198 }
199}
diff --git a/OpenSim/Region/OptionalModules/Grid/Interregion/RemotingObject.cs b/OpenSim/Region/OptionalModules/Grid/Interregion/RemotingObject.cs
new file mode 100644
index 0000000..b09c848
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Grid/Interregion/RemotingObject.cs
@@ -0,0 +1,77 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenSim.Framework;
31
32namespace OpenSim.Region.CoreModules.Grid.Interregion
33{
34 public class RemotingObject : MarshalByRefObject
35 {
36 private readonly Location[] m_coords;
37 private readonly Dictionary<Type, Object> m_interfaces = new Dictionary<Type, object>();
38
39 public RemotingObject(Dictionary<Type, Object> myInterfaces, Location[] coords)
40 {
41 m_interfaces = myInterfaces;
42 m_coords = coords;
43 }
44
45 public Location[] GetLocations()
46 {
47 return (Location[]) m_coords.Clone();
48 }
49
50 public string[] GetInterfaces()
51 {
52 string[] interfaces = new string[m_interfaces.Count];
53 int i = 0;
54
55 foreach (KeyValuePair<Type, object> pair in m_interfaces)
56 {
57 interfaces[i++] = pair.Key.FullName;
58 }
59
60 return interfaces;
61 }
62
63 /// <summary>
64 /// Returns a registered interface availible to neighbouring regions.
65 /// </summary>
66 /// <typeparam name="T">The type of interface you wish to request</typeparam>
67 /// <returns>A MarshalByRefObject inherited from this region inheriting the interface requested.</returns>
68 /// <remarks>All registered interfaces <b>MUST</b> inherit from MarshalByRefObject and use only serialisable types.</remarks>
69 public T RequestInterface<T>()
70 {
71 if (m_interfaces.ContainsKey(typeof (T)))
72 return (T) m_interfaces[typeof (T)];
73
74 throw new NotSupportedException("No such interface registered.");
75 }
76 }
77}
diff --git a/OpenSim/Region/OptionalModules/Python/PythonAPI/Console.cs b/OpenSim/Region/OptionalModules/Python/PythonAPI/Console.cs
new file mode 100644
index 0000000..215a9ad
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Python/PythonAPI/Console.cs
@@ -0,0 +1,48 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using log4net;
31
32namespace OpenSim.Region.Modules.Python.PythonAPI
33{
34 class Console
35 {
36 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
37
38 public void WriteLine(string txt)
39 {
40 m_log.Info(txt);
41 }
42
43 public void WriteLine(string txt, params Object[] e)
44 {
45 m_log.Info(String.Format(txt, e));
46 }
47 }
48}
diff --git a/OpenSim/Region/OptionalModules/Python/PythonModule.cs b/OpenSim/Region/OptionalModules/Python/PythonModule.cs
new file mode 100644
index 0000000..5dedac2
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Python/PythonModule.cs
@@ -0,0 +1,71 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Security.Policy;
32using System.Text;
33using IronPython.Hosting;
34using log4net;
35using Nini.Config;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.Modules.Python
40{
41 class PythonModule : IRegionModule
42 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 private PythonEngine m_python;
45
46 public void Initialise(Scene scene, IConfigSource source)
47 {
48 }
49
50 public void PostInitialise()
51 {
52 m_log.Info("[PYTHON] Initialising IronPython engine.");
53 m_python = new PythonEngine();
54 m_python.AddToPath(System.Environment.CurrentDirectory + System.IO.Path.DirectorySeparatorChar + "Python");
55 }
56
57 public void Close()
58 {
59 }
60
61 public string Name
62 {
63 get { return "PythonModule"; }
64 }
65
66 public bool IsSharedModule
67 {
68 get { return true; }
69 }
70 }
71}
diff --git a/OpenSim/Region/OptionalModules/README b/OpenSim/Region/OptionalModules/README
new file mode 100644
index 0000000..0fe7b87
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/README
@@ -0,0 +1,9 @@
1= OpenSim.Region.OptionalModules =
2
3The modules in this part of the OpenSim source tree are candidates for forge. For the time being, until we have reached consensus on
4
5 (a) what should be core or optional
6 (b) that we have reached a stable API
7 (c) how to maintain optional modules
8
9we will keep these modules in-tree. \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/SvnSerialiser/Properties/AssemblyInfo.cs b/OpenSim/Region/OptionalModules/SvnSerialiser/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..165fcea
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/SvnSerialiser/Properties/AssemblyInfo.cs
@@ -0,0 +1,62 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Reflection;
29using System.Runtime.InteropServices;
30
31// General information about an assembly is controlled through the following
32// set of attributes. Change these attribute values to modify the information
33// associated with an assembly.
34[assembly: AssemblyTitle("SvnSerialiser")]
35[assembly: AssemblyDescription("")]
36[assembly: AssemblyConfiguration("")]
37[assembly: AssemblyCompany("")]
38[assembly: AssemblyProduct("SvnSerialiser")]
39[assembly: AssemblyCopyright("Copyright (c) 2008")]
40[assembly: AssemblyTrademark("")]
41[assembly: AssemblyCulture("")]
42
43// Setting ComVisible to false makes the types in this assembly not visible
44// to COM components. If you need to access a type in this assembly from
45// COM, set the ComVisible attribute to true on that type.
46[assembly: ComVisible(false)]
47
48// The following GUID is for the ID of the typelib if this project is exposed to COM
49[assembly: Guid("c0893655-0c18-4dd7-8b5b-5f58ab1ec6c7")]
50
51// Version information for an assembly consists of the following four values:
52//
53// Major Version
54// Minor Version
55// Build Number
56// Revision
57//
58// You can specify all the values or you can default the Build and Revision Numbers
59// by using the '*' as shown below:
60// [assembly: AssemblyVersion("1.0.*")]
61[assembly: AssemblyVersion("1.0.0.0")]
62[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Region/OptionalModules/SvnSerialiser/SvnBackupModule.cs b/OpenSim/Region/OptionalModules/SvnSerialiser/SvnBackupModule.cs
new file mode 100644
index 0000000..c4fc584
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/SvnSerialiser/SvnBackupModule.cs
@@ -0,0 +1,396 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Timers;
33using log4net;
34using Nini.Config;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.CoreModules.World.Serialiser;
37using OpenSim.Region.CoreModules.World.Terrain;
38using OpenSim.Region.Framework.Scenes;
39using PumaCode.SvnDotNet.AprSharp;
40using PumaCode.SvnDotNet.SubversionSharp;
41using Slash = System.IO.Path;
42
43namespace OpenSim.Region.Modules.SvnSerialiser
44{
45 public class SvnBackupModule : IRegionModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private readonly List<Scene> m_scenes = new List<Scene>();
49 private readonly Timer m_timer = new Timer();
50
51 private bool m_enabled = false;
52 private bool m_installBackupOnLoad = false;
53 private IRegionSerialiserModule m_serialiser;
54 private bool m_svnAutoSave = false;
55 private SvnClient m_svnClient;
56 private string m_svndir = "SVNmodule" + Slash.DirectorySeparatorChar + "repo";
57 private string m_svnpass = "password";
58
59 private TimeSpan m_svnperiod = new TimeSpan(0, 0, 15, 0, 0);
60 private string m_svnurl = "svn://insert.Your.svn/here/";
61 private string m_svnuser = "username";
62
63 #region SvnModule Core
64
65 /// <summary>
66 /// Exports a specified scene to the SVN repo directory, then commits.
67 /// </summary>
68 /// <param name="scene">The scene to export</param>
69 public void SaveRegion(Scene scene)
70 {
71 List<string> svnfilenames = CreateAndAddExport(scene);
72
73 m_svnClient.Commit3(svnfilenames, true, false);
74 m_log.Info("[SVNBACKUP]: Region backup successful (" + scene.RegionInfo.RegionName + ").");
75 }
76
77 /// <summary>
78 /// Saves all registered scenes to the SVN repo, then commits.
79 /// </summary>
80 public void SaveAllRegions()
81 {
82 List<string> svnfilenames = new List<string>();
83 List<string> regions = new List<string>();
84
85 foreach (Scene scene in m_scenes)
86 {
87 svnfilenames.AddRange(CreateAndAddExport(scene));
88 regions.Add("'" + scene.RegionInfo.RegionName + "' ");
89 }
90
91 m_svnClient.Commit3(svnfilenames, true, false);
92 m_log.Info("[SVNBACKUP]: Server backup successful (" + String.Concat(regions.ToArray()) + ").");
93 }
94
95 private List<string> CreateAndAddExport(Scene scene)
96 {
97 m_log.Info("[SVNBACKUP]: Saving a region to SVN with name " + scene.RegionInfo.RegionName);
98
99 List<string> filenames = m_serialiser.SerialiseRegion(scene, m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID + Slash.DirectorySeparatorChar);
100
101 try
102 {
103 m_svnClient.Add3(m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID, true, false, false);
104 }
105 catch (SvnException)
106 {
107 }
108
109 List<string> svnfilenames = new List<string>();
110 foreach (string filename in filenames)
111 svnfilenames.Add(m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID + Slash.DirectorySeparatorChar + filename);
112 svnfilenames.Add(m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID);
113
114 return svnfilenames;
115 }
116
117 public void LoadRegion(Scene scene)
118 {
119 IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
120 if (serialiser != null)
121 {
122 serialiser.LoadPrimsFromXml2(
123 scene,
124 m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID
125 + Slash.DirectorySeparatorChar + "objects.xml");
126
127 scene.RequestModuleInterface<ITerrainModule>().LoadFromFile(
128 m_svndir + Slash.DirectorySeparatorChar + scene.RegionInfo.RegionID
129 + Slash.DirectorySeparatorChar + "heightmap.r32");
130
131 m_log.Info("[SVNBACKUP]: Region load successful (" + scene.RegionInfo.RegionName + ").");
132 }
133 else
134 {
135 m_log.ErrorFormat(
136 "[SVNBACKUP]: Region load of {0} failed - no serialisation module available",
137 scene.RegionInfo.RegionName);
138 }
139 }
140
141 private void CheckoutSvn()
142 {
143 m_svnClient.Checkout2(m_svnurl, m_svndir, Svn.Revision.Head, Svn.Revision.Head, true, false);
144 }
145
146 private void CheckoutSvn(SvnRevision revision)
147 {
148 m_svnClient.Checkout2(m_svnurl, m_svndir, revision, revision, true, false);
149 }
150
151 // private void CheckoutSvnPartial(string subdir)
152 // {
153 // if (!Directory.Exists(m_svndir + Slash.DirectorySeparatorChar + subdir))
154 // Directory.CreateDirectory(m_svndir + Slash.DirectorySeparatorChar + subdir);
155
156 // m_svnClient.Checkout2(m_svnurl + "/" + subdir, m_svndir, Svn.Revision.Head, Svn.Revision.Head, true, false);
157 // }
158
159 // private void CheckoutSvnPartial(string subdir, SvnRevision revision)
160 // {
161 // if (!Directory.Exists(m_svndir + Slash.DirectorySeparatorChar + subdir))
162 // Directory.CreateDirectory(m_svndir + Slash.DirectorySeparatorChar + subdir);
163
164 // m_svnClient.Checkout2(m_svnurl + "/" + subdir, m_svndir, revision, revision, true, false);
165 // }
166
167 #endregion
168
169 #region SvnDotNet Callbacks
170
171 private SvnError SimpleAuth(out SvnAuthCredSimple svnCredentials, IntPtr baton,
172 AprString realm, AprString username, bool maySave, AprPool pool)
173 {
174 svnCredentials = SvnAuthCredSimple.Alloc(pool);
175 svnCredentials.Username = new AprString(m_svnuser, pool);
176 svnCredentials.Password = new AprString(m_svnpass, pool);
177 svnCredentials.MaySave = false;
178 return SvnError.NoError;
179 }
180
181 private SvnError GetCommitLogCallback(out AprString logMessage, out SvnPath tmpFile, AprArray commitItems, IntPtr baton, AprPool pool)
182 {
183 if (!commitItems.IsNull)
184 {
185 foreach (SvnClientCommitItem2 item in commitItems)
186 {
187 m_log.Debug("[SVNBACKUP]: ... " + Path.GetFileName(item.Path.ToString()) + " (" + item.Kind.ToString() + ") r" + item.Revision.ToString());
188 }
189 }
190
191 string msg = "Region Backup (" + System.Environment.MachineName + " at " + DateTime.UtcNow + " UTC)";
192
193 m_log.Debug("[SVNBACKUP]: Saved with message: " + msg);
194
195 logMessage = new AprString(msg, pool);
196 tmpFile = new SvnPath(pool);
197
198 return (SvnError.NoError);
199 }
200
201 #endregion
202
203 #region IRegionModule Members
204
205 public void Initialise(Scene scene, IConfigSource source)
206 {
207 try
208 {
209 if (!source.Configs["SVN"].GetBoolean("Enabled", false))
210 return;
211
212 m_enabled = true;
213
214 m_svndir = source.Configs["SVN"].GetString("Directory", m_svndir);
215 m_svnurl = source.Configs["SVN"].GetString("URL", m_svnurl);
216 m_svnuser = source.Configs["SVN"].GetString("Username", m_svnuser);
217 m_svnpass = source.Configs["SVN"].GetString("Password", m_svnpass);
218 m_installBackupOnLoad = source.Configs["SVN"].GetBoolean("ImportOnStartup", m_installBackupOnLoad);
219 m_svnAutoSave = source.Configs["SVN"].GetBoolean("Autosave", m_svnAutoSave);
220 m_svnperiod = new TimeSpan(0, source.Configs["SVN"].GetInt("AutosavePeriod", (int) m_svnperiod.TotalMinutes), 0);
221 }
222 catch (Exception)
223 {
224 }
225
226 lock (m_scenes)
227 {
228 m_scenes.Add(scene);
229 }
230 //Only register it once, to prevent command being executed x*region times
231 if (m_scenes.Count == 1)
232 {
233 scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
234 }
235 }
236
237 public void PostInitialise()
238 {
239 if (m_enabled == false)
240 return;
241
242 if (m_svnAutoSave)
243 {
244 m_timer.Interval = m_svnperiod.TotalMilliseconds;
245 m_timer.Elapsed += m_timer_Elapsed;
246 m_timer.AutoReset = true;
247 m_timer.Start();
248 }
249
250 m_log.Info("[SVNBACKUP]: Connecting to SVN server " + m_svnurl + " ...");
251 SetupSvnProvider();
252
253 m_log.Info("[SVNBACKUP]: Creating repository in " + m_svndir + ".");
254 CreateSvnDirectory();
255 CheckoutSvn();
256 SetupSerialiser();
257
258 if (m_installBackupOnLoad)
259 {
260 m_log.Info("[SVNBACKUP]: Importing latest SVN revision to scenes...");
261 foreach (Scene scene in m_scenes)
262 {
263 LoadRegion(scene);
264 }
265 }
266 }
267
268 public void Close()
269 {
270 }
271
272 public string Name
273 {
274 get { return "SvnBackupModule"; }
275 }
276
277 public bool IsSharedModule
278 {
279 get { return true; }
280 }
281
282 #endregion
283
284 private void EventManager_OnPluginConsole(string[] args)
285 {
286 if (args[0] == "svn" && args[1] == "save")
287 {
288 SaveAllRegions();
289 }
290 if (args.Length == 2)
291 {
292 if (args[0] == "svn" && args[1] == "load")
293 {
294 LoadAllScenes();
295 }
296 }
297 if (args.Length == 3)
298 {
299 if (args[0] == "svn" && args[1] == "load")
300 {
301 LoadAllScenes(Int32.Parse(args[2]));
302 }
303 }
304 if (args.Length == 3)
305 {
306 if (args[0] == "svn" && args[1] == "load-region")
307 {
308 LoadScene(args[2]);
309 }
310 }
311 if (args.Length == 4)
312 {
313 if (args[0] == "svn" && args[1] == "load-region")
314 {
315 LoadScene(args[2], Int32.Parse(args[3]));
316 }
317 }
318 }
319
320 public void LoadScene(string name)
321 {
322 CheckoutSvn();
323
324 foreach (Scene scene in m_scenes)
325 {
326 if (scene.RegionInfo.RegionName.ToLower().Equals(name.ToLower()))
327 {
328 LoadRegion(scene);
329 return;
330 }
331 }
332 m_log.Warn("[SVNBACKUP]: No region loaded - unable to find matching name.");
333 }
334
335 public void LoadScene(string name, int revision)
336 {
337 CheckoutSvn(new SvnRevision(revision));
338
339 foreach (Scene scene in m_scenes)
340 {
341 if (scene.RegionInfo.RegionName.ToLower().Equals(name.ToLower()))
342 {
343 LoadRegion(scene);
344 return;
345 }
346 }
347 m_log.Warn("[SVNBACKUP]: No region loaded - unable to find matching name.");
348 }
349
350 public void LoadAllScenes()
351 {
352 CheckoutSvn();
353
354 foreach (Scene scene in m_scenes)
355 {
356 LoadRegion(scene);
357 }
358 }
359
360 public void LoadAllScenes(int revision)
361 {
362 CheckoutSvn(new SvnRevision(revision));
363
364 foreach (Scene scene in m_scenes)
365 {
366 LoadRegion(scene);
367 }
368 }
369
370 private void m_timer_Elapsed(object sender, ElapsedEventArgs e)
371 {
372 SaveAllRegions();
373 }
374
375 private void SetupSerialiser()
376 {
377 if (m_scenes.Count > 0)
378 m_serialiser = m_scenes[0].RequestModuleInterface<IRegionSerialiserModule>();
379 }
380
381 private void SetupSvnProvider()
382 {
383 m_svnClient = new SvnClient();
384 m_svnClient.AddUsernameProvider();
385 m_svnClient.AddPromptProvider(new SvnAuthProviderObject.SimplePrompt(SimpleAuth), IntPtr.Zero, 2);
386 m_svnClient.OpenAuth();
387 m_svnClient.Context.LogMsgFunc2 = new SvnDelegate(new SvnClient.GetCommitLog2(GetCommitLogCallback));
388 }
389
390 private void CreateSvnDirectory()
391 {
392 if (!Directory.Exists(m_svndir))
393 Directory.CreateDirectory(m_svndir);
394 }
395 }
396}
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
new file mode 100644
index 0000000..3ba8a97
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -0,0 +1,1060 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using OpenMetaverse;
32using OpenMetaverse.Packets;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Scenes;
35
36namespace OpenSim.Region.OptionalModules.World.NPC
37{
38 public class NPCAvatar : IClientAPI
39 {
40 private readonly string m_firstname;
41 private readonly string m_lastname;
42 private readonly Vector3 m_startPos;
43 private readonly UUID m_uuid = UUID.Random();
44 private readonly Scene m_scene;
45
46
47 public NPCAvatar(string firstname, string lastname, Vector3 position, Scene scene)
48 {
49 m_firstname = firstname;
50 m_lastname = lastname;
51 m_startPos = position;
52 m_scene = scene;
53 }
54
55 public IScene Scene
56 {
57 get { return m_scene; }
58 }
59
60 public void Say(string message)
61 {
62 SendOnChatFromClient(message, ChatTypeEnum.Say);
63 }
64
65 public void Shout(string message)
66 {
67 SendOnChatFromClient(message, ChatTypeEnum.Shout);
68 }
69
70 public void Whisper(string message)
71 {
72 SendOnChatFromClient(message, ChatTypeEnum.Whisper);
73 }
74
75 public void Broadcast(string message)
76 {
77 SendOnChatFromClient(message, ChatTypeEnum.Broadcast);
78 }
79
80 public void GiveMoney(UUID target, int amount)
81 {
82 OnMoneyTransferRequest(m_uuid, target, amount, 1, "Payment");
83 }
84
85 public void InstantMessage(UUID target, string message)
86 {
87 OnInstantMessage(this, new GridInstantMessage(m_scene,
88 m_uuid, m_firstname + " " + m_lastname,
89 target, 0, false, message,
90 UUID.Zero, false, Position, new byte[0]));
91 }
92
93 public void SendAgentOffline(UUID[] agentIDs)
94 {
95
96 }
97
98 public void SendAgentOnline(UUID[] agentIDs)
99 {
100
101 }
102 public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, Quaternion SitOrientation, bool autopilot,
103 Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook)
104 {
105
106 }
107
108 public void SendAdminResponse(UUID Token, uint AdminLevel)
109 {
110
111 }
112
113 public void SendGroupMembership(GroupMembershipData[] GroupMembership)
114 {
115
116 }
117
118 public UUID GetDefaultAnimation(string name)
119 {
120 return UUID.Zero;
121 }
122
123 public Vector3 Position
124 {
125 get { return m_scene.Entities[m_uuid].AbsolutePosition; }
126 set { m_scene.Entities[m_uuid].AbsolutePosition = value; }
127 }
128
129 public bool SendLogoutPacketWhenClosing
130 {
131 set { }
132 }
133
134 #region Internal Functions
135
136 private void SendOnChatFromClient(string message, ChatTypeEnum chatType)
137 {
138 OSChatMessage chatFromClient = new OSChatMessage();
139 chatFromClient.Channel = 0;
140 chatFromClient.From = Name;
141 chatFromClient.Message = message;
142 chatFromClient.Position = StartPos;
143 chatFromClient.Scene = m_scene;
144 chatFromClient.Sender = this;
145 chatFromClient.SenderUUID = AgentId;
146 chatFromClient.Type = chatType;
147
148 OnChatFromClient(this, chatFromClient);
149 }
150
151 #endregion
152
153 #region Event Definitions IGNORE
154
155// disable warning: public events constituting public API
156#pragma warning disable 67
157 public event Action<IClientAPI> OnLogout;
158 public event ObjectPermissions OnObjectPermissions;
159
160 public event MoneyTransferRequest OnMoneyTransferRequest;
161 public event ParcelBuy OnParcelBuy;
162 public event Action<IClientAPI> OnConnectionClosed;
163 public event GenericMessage OnGenericMessage;
164 public event ImprovedInstantMessage OnInstantMessage;
165 public event ChatMessage OnChatFromClient;
166 public event TextureRequest OnRequestTexture;
167 public event RezObject OnRezObject;
168 public event ModifyTerrain OnModifyTerrain;
169 public event SetAppearance OnSetAppearance;
170 public event AvatarNowWearing OnAvatarNowWearing;
171 public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
172 public event UUIDNameRequest OnDetachAttachmentIntoInv;
173 public event ObjectAttach OnObjectAttach;
174 public event ObjectDeselect OnObjectDetach;
175 public event ObjectDrop OnObjectDrop;
176 public event StartAnim OnStartAnim;
177 public event StopAnim OnStopAnim;
178 public event LinkObjects OnLinkObjects;
179 public event DelinkObjects OnDelinkObjects;
180 public event RequestMapBlocks OnRequestMapBlocks;
181 public event RequestMapName OnMapNameRequest;
182 public event TeleportLocationRequest OnTeleportLocationRequest;
183 public event TeleportLandmarkRequest OnTeleportLandmarkRequest;
184 public event DisconnectUser OnDisconnectUser;
185 public event RequestAvatarProperties OnRequestAvatarProperties;
186 public event SetAlwaysRun OnSetAlwaysRun;
187
188 public event DeRezObject OnDeRezObject;
189 public event Action<IClientAPI> OnRegionHandShakeReply;
190 public event GenericCall2 OnRequestWearables;
191 public event GenericCall2 OnCompleteMovementToRegion;
192 public event UpdateAgent OnAgentUpdate;
193 public event AgentRequestSit OnAgentRequestSit;
194 public event AgentSit OnAgentSit;
195 public event AvatarPickerRequest OnAvatarPickerRequest;
196 public event Action<IClientAPI> OnRequestAvatarsData;
197 public event AddNewPrim OnAddPrim;
198 public event RequestGodlikePowers OnRequestGodlikePowers;
199 public event GodKickUser OnGodKickUser;
200 public event ObjectDuplicate OnObjectDuplicate;
201 public event GrabObject OnGrabObject;
202 public event ObjectSelect OnDeGrabObject;
203 public event MoveObject OnGrabUpdate;
204 public event ViewerEffectEventHandler OnViewerEffect;
205
206 public event FetchInventory OnAgentDataUpdateRequest;
207 public event TeleportLocationRequest OnSetStartLocationRequest;
208
209 public event UpdateShape OnUpdatePrimShape;
210 public event ObjectExtraParams OnUpdateExtraParams;
211 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
212 public event ObjectSelect OnObjectSelect;
213 public event GenericCall7 OnObjectDescription;
214 public event GenericCall7 OnObjectName;
215 public event GenericCall7 OnObjectClickAction;
216 public event GenericCall7 OnObjectMaterial;
217 public event UpdatePrimFlags OnUpdatePrimFlags;
218 public event UpdatePrimTexture OnUpdatePrimTexture;
219 public event UpdateVector OnUpdatePrimGroupPosition;
220 public event UpdateVector OnUpdatePrimSinglePosition;
221 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
222 public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation;
223 public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation;
224 public event UpdateVector OnUpdatePrimScale;
225 public event UpdateVector OnUpdatePrimGroupScale;
226 public event StatusChange OnChildAgentStatus;
227 public event GenericCall2 OnStopMovement;
228 public event Action<UUID> OnRemoveAvatar;
229
230 public event CreateNewInventoryItem OnCreateNewInventoryItem;
231 public event CreateInventoryFolder OnCreateNewInventoryFolder;
232 public event UpdateInventoryFolder OnUpdateInventoryFolder;
233 public event MoveInventoryFolder OnMoveInventoryFolder;
234 public event RemoveInventoryFolder OnRemoveInventoryFolder;
235 public event RemoveInventoryItem OnRemoveInventoryItem;
236 public event FetchInventoryDescendents OnFetchInventoryDescendents;
237 public event PurgeInventoryDescendents OnPurgeInventoryDescendents;
238 public event FetchInventory OnFetchInventory;
239 public event RequestTaskInventory OnRequestTaskInventory;
240 public event UpdateInventoryItem OnUpdateInventoryItem;
241 public event CopyInventoryItem OnCopyInventoryItem;
242 public event MoveInventoryItem OnMoveInventoryItem;
243 public event UDPAssetUploadRequest OnAssetUploadRequest;
244 public event XferReceive OnXferReceive;
245 public event RequestXfer OnRequestXfer;
246 public event AbortXfer OnAbortXfer;
247 public event ConfirmXfer OnConfirmXfer;
248 public event RezScript OnRezScript;
249 public event UpdateTaskInventory OnUpdateTaskInventory;
250 public event MoveTaskInventory OnMoveTaskItem;
251 public event RemoveTaskInventory OnRemoveTaskItem;
252 public event RequestAsset OnRequestAsset;
253
254 public event UUIDNameRequest OnNameFromUUIDRequest;
255 public event UUIDNameRequest OnUUIDGroupNameRequest;
256
257 public event ParcelPropertiesRequest OnParcelPropertiesRequest;
258 public event ParcelDivideRequest OnParcelDivideRequest;
259 public event ParcelJoinRequest OnParcelJoinRequest;
260 public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest;
261 public event ParcelAbandonRequest OnParcelAbandonRequest;
262 public event ParcelGodForceOwner OnParcelGodForceOwner;
263 public event ParcelReclaim OnParcelReclaim;
264 public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest;
265 public event ParcelAccessListRequest OnParcelAccessListRequest;
266 public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest;
267 public event ParcelSelectObjects OnParcelSelectObjects;
268 public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest;
269 public event ObjectDeselect OnObjectDeselect;
270 public event RegionInfoRequest OnRegionInfoRequest;
271 public event EstateCovenantRequest OnEstateCovenantRequest;
272 public event RequestTerrain OnRequestTerrain;
273 public event RequestTerrain OnUploadTerrain;
274 public event ObjectDuplicateOnRay OnObjectDuplicateOnRay;
275
276 public event FriendActionDelegate OnApproveFriendRequest;
277 public event FriendActionDelegate OnDenyFriendRequest;
278 public event FriendshipTermination OnTerminateFriendship;
279
280 public event EconomyDataRequest OnEconomyDataRequest;
281 public event MoneyBalanceRequest OnMoneyBalanceRequest;
282 public event UpdateAvatarProperties OnUpdateAvatarProperties;
283
284 public event ObjectIncludeInSearch OnObjectIncludeInSearch;
285 public event UUIDNameRequest OnTeleportHomeRequest;
286
287 public event ScriptAnswer OnScriptAnswer;
288 public event RequestPayPrice OnRequestPayPrice;
289 public event ObjectSaleInfo OnObjectSaleInfo;
290 public event ObjectBuy OnObjectBuy;
291 public event BuyObjectInventory OnBuyObjectInventory;
292 public event AgentSit OnUndo;
293
294 public event ForceReleaseControls OnForceReleaseControls;
295 public event GodLandStatRequest OnLandStatRequest;
296 public event RequestObjectPropertiesFamily OnObjectGroupRequest;
297
298 public event DetailedEstateDataRequest OnDetailedEstateDataRequest;
299 public event SetEstateFlagsRequest OnSetEstateFlagsRequest;
300 public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture;
301 public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture;
302 public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights;
303 public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest;
304 public event SetRegionTerrainSettings OnSetRegionTerrainSettings;
305 public event BakeTerrain OnBakeTerrain;
306 public event EstateRestartSimRequest OnEstateRestartSimRequest;
307 public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest;
308 public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest;
309 public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest;
310 public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest;
311 public event EstateDebugRegionRequest OnEstateDebugRegionRequest;
312 public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest;
313 public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest;
314 public event EstateChangeInfo OnEstateChangeInfo;
315 public event ScriptReset OnScriptReset;
316 public event GetScriptRunning OnGetScriptRunning;
317 public event SetScriptRunning OnSetScriptRunning;
318 public event UpdateVector OnAutoPilotGo;
319
320 public event TerrainUnacked OnUnackedTerrain;
321
322 public event RegionHandleRequest OnRegionHandleRequest;
323 public event ParcelInfoRequest OnParcelInfoRequest;
324
325 public event ActivateGesture OnActivateGesture;
326 public event DeactivateGesture OnDeactivateGesture;
327 public event ObjectOwner OnObjectOwner;
328
329 public event DirPlacesQuery OnDirPlacesQuery;
330 public event DirFindQuery OnDirFindQuery;
331 public event DirLandQuery OnDirLandQuery;
332 public event DirPopularQuery OnDirPopularQuery;
333 public event DirClassifiedQuery OnDirClassifiedQuery;
334 public event EventInfoRequest OnEventInfoRequest;
335 public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime;
336
337 public event MapItemRequest OnMapItemRequest;
338
339 public event OfferCallingCard OnOfferCallingCard;
340 public event AcceptCallingCard OnAcceptCallingCard;
341 public event DeclineCallingCard OnDeclineCallingCard;
342 public event SoundTrigger OnSoundTrigger;
343
344 public event StartLure OnStartLure;
345 public event TeleportLureRequest OnTeleportLureRequest;
346 public event NetworkStats OnNetworkStatsUpdate;
347
348 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
349 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
350 public event ClassifiedDelete OnClassifiedDelete;
351 public event ClassifiedDelete OnClassifiedGodDelete;
352
353 public event EventNotificationAddRequest OnEventNotificationAddRequest;
354 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
355 public event EventGodDelete OnEventGodDelete;
356
357 public event ParcelDwellRequest OnParcelDwellRequest;
358
359 public event UserInfoRequest OnUserInfoRequest;
360 public event UpdateUserInfo OnUpdateUserInfo;
361
362#pragma warning restore 67
363
364 #endregion
365
366 public void ActivateGesture(UUID assetId, UUID gestureId)
367 {
368 }
369 public void DeactivateGesture(UUID assetId, UUID gestureId)
370 {
371 }
372
373 #region Overrriden Methods IGNORE
374
375 public virtual Vector3 StartPos
376 {
377 get { return m_startPos; }
378 set { }
379 }
380
381 public virtual UUID AgentId
382 {
383 get { return m_uuid; }
384 }
385
386 public UUID SessionId
387 {
388 get { return UUID.Zero; }
389 }
390
391 public UUID SecureSessionId
392 {
393 get { return UUID.Zero; }
394 }
395
396 public virtual string FirstName
397 {
398 get { return m_firstname; }
399 }
400
401 public virtual string LastName
402 {
403 get { return m_lastname; }
404 }
405
406 public virtual String Name
407 {
408 get { return FirstName + " " + LastName; }
409 }
410
411 public bool IsActive
412 {
413 get { return true; }
414 set { }
415 }
416
417 public UUID ActiveGroupId
418 {
419 get { return UUID.Zero; }
420 }
421
422 public string ActiveGroupName
423 {
424 get { return String.Empty; }
425 }
426
427 public ulong ActiveGroupPowers
428 {
429 get { return 0; }
430 }
431
432 public bool IsGroupMember(UUID groupID)
433 {
434 return false;
435 }
436
437 public ulong GetGroupPowers(UUID groupID)
438 {
439 return 0;
440 }
441
442 public virtual int NextAnimationSequenceNumber
443 {
444 get { return 1; }
445 }
446
447 public virtual void SendWearables(AvatarWearable[] wearables, int serial)
448 {
449 }
450
451 public virtual void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
452 {
453 }
454
455 public virtual void Kick(string message)
456 {
457 }
458
459 public virtual void SendStartPingCheck(byte seq)
460 {
461 }
462
463 public virtual void SendAvatarPickerReply(AvatarPickerReplyAgentDataArgs AgentData, List<AvatarPickerReplyDataArgs> Data)
464 {
465 }
466
467 public virtual void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle)
468 {
469
470 }
471
472 public virtual void SendKillObject(ulong regionHandle, uint localID)
473 {
474 }
475
476 public virtual void SetChildAgentThrottle(byte[] throttle)
477 {
478 }
479 public byte[] GetThrottlesPacked(float multiplier)
480 {
481 return new byte[0];
482 }
483
484
485 public virtual void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId)
486 {
487 }
488
489 public virtual void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName,
490 UUID fromAgentID, byte source, byte audible)
491 {
492 }
493
494 public virtual void SendChatMessage(byte[] message, byte type, Vector3 fromPos, string fromName,
495 UUID fromAgentID, byte source, byte audible)
496 {
497 }
498
499 public void SendInstantMessage(UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, uint timeStamp)
500 {
501
502 }
503
504 public void SendInstantMessage(UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, uint timeStamp, UUID transationID, bool fromGroup, byte[] binaryBucket)
505 {
506
507 }
508
509 public void SendGenericMessage(string method, List<string> message)
510 {
511
512 }
513
514 public virtual void SendLayerData(float[] map)
515 {
516 }
517
518 public virtual void SendLayerData(int px, int py, float[] map)
519 {
520 }
521 public virtual void SendLayerData(int px, int py, float[] map, bool track)
522 {
523 }
524
525 public virtual void SendWindData(Vector2[] windSpeeds) { }
526
527 public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
528 {
529 }
530
531 public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint)
532 {
533 }
534
535 public virtual AgentCircuitData RequestClientInfo()
536 {
537 return new AgentCircuitData();
538 }
539
540 public virtual void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt,
541 IPEndPoint newRegionExternalEndPoint, string capsURL)
542 {
543 }
544
545 public virtual void SendMapBlock(List<MapBlockData> mapBlocks, uint flag)
546 {
547 }
548
549 public virtual void SendLocalTeleport(Vector3 position, Vector3 lookAt, uint flags)
550 {
551 }
552
553 public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
554 uint locationID, uint flags, string capsURL)
555 {
556 }
557
558 public virtual void SendTeleportFailed(string reason)
559 {
560 }
561
562 public virtual void SendTeleportLocationStart()
563 {
564 }
565
566 public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance)
567 {
568 }
569
570 public virtual void SendPayPrice(UUID objectID, int[] payPrice)
571 {
572 }
573
574 public virtual void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID,
575 uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation)
576 {
577 }
578
579 public virtual void SendAvatarTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID,
580 Vector3 position, Vector3 velocity, Quaternion rotation)
581 {
582 }
583
584 public virtual void SendCoarseLocationUpdate(List<Vector3> CoarseLocations)
585 {
586 }
587
588 public virtual void AttachObject(uint localID, Quaternion rotation, byte attachPoint, UUID ownerID)
589 {
590 }
591
592 public virtual void SendDialog(string objectname, UUID objectID, UUID ownerID, string msg, UUID textureID, int ch, string[] buttonlabels)
593 {
594 }
595
596 public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID,
597 PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel,
598 Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags,
599 UUID objectID, UUID ownerID, string text, byte[] color,
600 uint parentID,
601 byte[] particleSystem, byte clickAction, byte material)
602 {
603 }
604 public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID,
605 PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel,
606 Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags,
607 UUID objectID, UUID ownerID, string text, byte[] color,
608 uint parentID,
609 byte[] particleSystem, byte clickAction, byte material, byte[] textureanimation,
610 bool attachment, uint AttachmentPoint, UUID AssetId, UUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius)
611 {
612 }
613 public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID,
614 Vector3 position, Quaternion rotation, Vector3 velocity,
615 Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint)
616 {
617 }
618
619 public virtual void SendInventoryFolderDetails(UUID ownerID, UUID folderID,
620 List<InventoryItemBase> items,
621 List<InventoryFolderBase> folders,
622 bool fetchFolders,
623 bool fetchItems)
624 {
625 }
626
627 public virtual void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item)
628 {
629 }
630
631 public virtual void SendInventoryItemCreateUpdate(InventoryItemBase Item)
632 {
633 }
634
635 public virtual void SendRemoveInventoryItem(UUID itemID)
636 {
637 }
638
639 /// <see>IClientAPI.SendBulkUpdateInventory(InventoryItemBase)</see>
640 public virtual void SendBulkUpdateInventory(InventoryItemBase item)
641 {
642 }
643
644 public virtual void SendBulkUpdateInventory(InventoryFolderBase folderBase)
645 {}
646
647 public void SendTakeControls(int controls, bool passToAgent, bool TakeControls)
648 {
649 }
650
651 public virtual void SendTaskInventory(UUID taskID, short serial, byte[] fileName)
652 {
653 }
654
655 public virtual void SendXferPacket(ulong xferID, uint packet, byte[] data)
656 {
657 }
658
659 public virtual void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit,
660 int PriceGroupCreate, int PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor,
661 int PriceParcelClaim, float PriceParcelClaimFactor, int PriceParcelRent, int PricePublicObjectDecay,
662 int PricePublicObjectDelete, int PriceRentLight, int PriceUpload, int TeleportMinPrice, float TeleportPriceExponent)
663 {
664
665 }
666 public virtual void SendNameReply(UUID profileId, string firstname, string lastname)
667 {
668 }
669
670 public virtual void SendPreLoadSound(UUID objectID, UUID ownerID, UUID soundID)
671 {
672 }
673
674 public virtual void SendPlayAttachedSound(UUID soundID, UUID objectID, UUID ownerID, float gain,
675 byte flags)
676 {
677 }
678
679 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
680 {
681 }
682
683 public void SendAttachedSoundGainChange(UUID objectID, float gain)
684 {
685
686 }
687
688 public void SendAlertMessage(string message)
689 {
690 }
691
692 public void SendAgentAlertMessage(string message, bool modal)
693 {
694 }
695
696 public void SendSystemAlertMessage(string message)
697 {
698 }
699
700 public void SendLoadURL(string objectname, UUID objectID, UUID ownerID, bool groupOwned, string message,
701 string url)
702 {
703 }
704
705 public virtual void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args)
706 {
707 if (OnRegionHandShakeReply != null)
708 {
709 OnRegionHandShakeReply(this);
710 }
711
712 if (OnCompleteMovementToRegion != null)
713 {
714 OnCompleteMovementToRegion();
715 }
716 }
717 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
718 {
719 }
720
721 public void SendConfirmXfer(ulong xferID, uint PacketID)
722 {
723 }
724
725 public void SendXferRequest(ulong XferID, short AssetType, UUID vFileID, byte FilePath, byte[] FileName)
726 {
727 }
728
729 public void SendInitiateDownload(string simFileName, string clientFileName)
730 {
731 }
732
733 public void SendImageFirstPart(ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec)
734 {
735 }
736
737 public void SendImageNotFound(UUID imageid)
738 {
739 }
740
741 public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData)
742 {
743 }
744
745 public void SendShutdownConnectionNotice()
746 {
747 }
748
749 public void SendSimStats(SimStats stats)
750 {
751 }
752
753 public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID,
754 uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask,
755 uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category,
756 UUID LastOwnerID, string ObjectName, string Description)
757 {
758 }
759
760 public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID,
761 UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID,
762 UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName,
763 string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask,
764 uint BaseMask, byte saleType, int salePrice)
765 {
766 }
767
768 public bool AddMoney(int debit)
769 {
770 return false;
771 }
772
773 public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong time, uint dlen, uint ylen, float phase)
774 {
775 }
776
777 public void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks)
778 {
779 }
780
781 public void SendViewerTime(int phase)
782 {
783 }
784
785 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember,
786 string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL,
787 UUID partnerID)
788 {
789 }
790
791 public void SendAsset(AssetRequestToClient req)
792 {
793 }
794
795 public void SendTexture(AssetBase TextureAsset)
796 {
797 }
798
799 public void SetDebugPacketLevel(int newDebug)
800 {
801 }
802
803 public void InPacket(object NewPack)
804 {
805 }
806
807 public void ProcessInPacket(Packet NewPack)
808 {
809 }
810
811 public void Close(bool ShutdownCircuit)
812 {
813 }
814
815 public void Start()
816 {
817 }
818
819 public void Stop()
820 {
821 }
822
823 private uint m_circuitCode;
824
825 public uint CircuitCode
826 {
827 get { return m_circuitCode; }
828 set { m_circuitCode = value; }
829 }
830
831 public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message)
832 {
833
834 }
835 public void SendLogoutPacket()
836 {
837 }
838
839 public void Terminate()
840 {
841 }
842
843 public ClientInfo GetClientInfo()
844 {
845 return null;
846 }
847
848 public void SetClientInfo(ClientInfo info)
849 {
850 }
851
852 public void SendScriptQuestion(UUID objectID, string taskName, string ownerName, UUID itemID, int question)
853 {
854 }
855 public void SendHealth(float health)
856 {
857 }
858
859 public void SendEstateManagersList(UUID invoice, UUID[] EstateManagers, uint estateID)
860 {
861 }
862
863 public void SendBannedUserList(UUID invoice, EstateBan[] banlist, uint estateID)
864 {
865 }
866
867 public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args)
868 {
869 }
870 public void SendEstateCovenantInformation(UUID covenant)
871 {
872 }
873 public void SendDetailedEstateData(UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition, UUID covenant, string abuseEmail, UUID estateOwner)
874 {
875 }
876
877 public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, LandData landData, float simObjectBonusFactor,int parcelObjectCapacity, int simObjectCapacity, uint regionFlags)
878 {
879 }
880 public void SendLandAccessListData(List<UUID> avatars, uint accessFlag, int localLandID)
881 {
882 }
883 public void SendForceClientSelectObjects(List<uint> objectIDs)
884 {
885 }
886 public void SendLandObjectOwners(Dictionary<UUID, int> ownersAndCount)
887 {
888 }
889 public void SendLandParcelOverlay(byte[] data, int sequence_id)
890 {
891 }
892
893 public void SendGroupNameReply(UUID groupLLUID, string GroupName)
894 {
895 }
896
897 public void SendScriptRunningReply(UUID objectID, UUID itemID, bool running)
898 {
899 }
900
901 public void SendLandStatReply(uint reportType, uint requestFlags, uint resultCount, LandStatReportItem[] lsrpia)
902 {
903 }
904 #endregion
905
906
907 public void SendParcelMediaCommand(uint flags, ParcelMediaCommandEnum command, float time)
908 {
909 }
910
911 public void SendParcelMediaUpdate(string mediaUrl, UUID mediaTextureID,
912 byte autoScale, string mediaType, string mediaDesc, int mediaWidth, int mediaHeight,
913 byte mediaLoop)
914 {
915 }
916
917 public void SendSetFollowCamProperties (UUID objectID, SortedDictionary<int, float> parameters)
918 {
919 }
920
921 public void SendClearFollowCamProperties (UUID objectID)
922 {
923 }
924
925 public void SendRegionHandle (UUID regoinID, ulong handle)
926 {
927 }
928
929 public void SendParcelInfo (RegionInfo info, LandData land, UUID parcelID, uint x, uint y)
930 {
931 }
932
933 public void SetClientOption(string option, string value)
934 {
935 }
936
937 public string GetClientOption(string option)
938 {
939 return string.Empty;
940 }
941
942 public void SendScriptTeleportRequest (string objName, string simName, Vector3 pos, Vector3 lookAt)
943 {
944 }
945
946 public void SendDirPlacesReply(UUID queryID, DirPlacesReplyData[] data)
947 {
948 }
949
950 public void SendDirPeopleReply(UUID queryID, DirPeopleReplyData[] data)
951 {
952 }
953
954 public void SendDirEventsReply(UUID queryID, DirEventsReplyData[] data)
955 {
956 }
957
958 public void SendDirGroupsReply(UUID queryID, DirGroupsReplyData[] data)
959 {
960 }
961
962 public void SendDirClassifiedReply(UUID queryID, DirClassifiedReplyData[] data)
963 {
964 }
965
966 public void SendDirLandReply(UUID queryID, DirLandReplyData[] data)
967 {
968 }
969
970 public void SendDirPopularReply(UUID queryID, DirPopularReplyData[] data)
971 {
972 }
973
974 public void SendMapItemReply(mapItemReply[] replies, uint mapitemtype, uint flags)
975 {
976 }
977
978 public void KillEndDone()
979 {
980 }
981
982 public void SendEventInfoReply (EventData info)
983 {
984 }
985
986 public void SendOfferCallingCard (UUID destID, UUID transactionID)
987 {
988 }
989
990 public void SendAcceptCallingCard (UUID transactionID)
991 {
992 }
993
994 public void SendDeclineCallingCard (UUID transactionID)
995 {
996 }
997
998 public void SendJoinGroupReply(UUID groupID, bool success)
999 {
1000 }
1001
1002 public void SendEjectGroupMemberReply(UUID agentID, UUID groupID, bool success)
1003 {
1004 }
1005
1006 public void SendLeaveGroupReply(UUID groupID, bool success)
1007 {
1008 }
1009
1010 public void SendAvatarGroupsReply(UUID avatarID, GroupMembershipData[] data)
1011 {
1012 }
1013
1014 public void SendTerminateFriend(UUID exFriendID)
1015 {
1016 }
1017
1018 #region IClientAPI Members
1019
1020
1021 public bool AddGenericPacketHandler(string MethodName, GenericMessage handler)
1022 {
1023 throw new NotImplementedException();
1024 }
1025
1026 public void SendAvatarClassifiedReply(UUID targetID, UUID[] classifiedID, string[] name)
1027 {
1028 }
1029
1030 public void SendClassifiedInfoReply(UUID classifiedID, UUID creatorID, uint creationDate, uint expirationDate, uint category, string name, string description, UUID parcelID, uint parentEstate, UUID snapshotID, string simName, Vector3 globalPos, string parcelName, byte classifiedFlags, int price)
1031 {
1032 }
1033
1034 public void SendAgentDropGroup(UUID groupID)
1035 {
1036 }
1037
1038 public void SendAvatarNotesReply(UUID targetID, string text)
1039 {
1040 }
1041
1042 public void SendAvatarPicksReply(UUID targetID, Dictionary<UUID, string> picks)
1043 {
1044 }
1045
1046 public void SendAvatarClassifiedReply(UUID targetID, Dictionary<UUID, string> classifieds)
1047 {
1048 }
1049
1050 public void SendParcelDwellReply(int localID, UUID parcelID, float dwell)
1051 {
1052 }
1053
1054 public void SendUserInfoReply(bool imViaEmail, bool visible, string email)
1055 {
1056 }
1057
1058 #endregion
1059 }
1060}
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
new file mode 100644
index 0000000..9dace33
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
@@ -0,0 +1,68 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenMetaverse;
29using Nini.Config;
30using OpenSim.Region.Framework.Interfaces;
31using OpenSim.Region.Framework.Scenes;
32
33namespace OpenSim.Region.OptionalModules.World.NPC
34{
35 public class NPCModule : IRegionModule
36 {
37 // private const bool m_enabled = false;
38
39 public void Initialise(Scene scene, IConfigSource source)
40 {
41 // if (m_enabled)
42 // {
43 // NPCAvatar testAvatar = new NPCAvatar("Jack", "NPC", new Vector3(128, 128, 40), scene);
44 // NPCAvatar testAvatar2 = new NPCAvatar("Jill", "NPC", new Vector3(136, 128, 40), scene);
45 // scene.AddNewClient(testAvatar, false);
46 // scene.AddNewClient(testAvatar2, false);
47 // }
48 }
49
50 public void PostInitialise()
51 {
52 }
53
54 public void Close()
55 {
56 }
57
58 public string Name
59 {
60 get { return "NPCModule"; }
61 }
62
63 public bool IsSharedModule
64 {
65 get { return true; }
66 }
67 }
68}
diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
new file mode 100644
index 0000000..94ebcac
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
@@ -0,0 +1,304 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Timers;
32using OpenMetaverse;
33using log4net;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.OptionalModules.World.TreePopulator
40{
41 /// <summary>
42 /// Version 2.0 - Very hacky compared to the original. Will fix original and release as 0.3 later.
43 /// </summary>
44 public class TreePopulatorModule : IRegionModule
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 private Scene m_scene;
48
49 public double m_tree_density = 50.0; // Aim for this many per region
50 public double m_tree_updates = 1000.0; // MS between updates
51 private bool m_active_trees = false;
52 private List<UUID> m_trees;
53 Timer CalculateTrees;
54
55 #region IRegionModule Members
56
57 public void Initialise(Scene scene, IConfigSource config)
58 {
59 try
60 {
61 m_tree_density = config.Configs["Trees"].GetDouble("tree_density", m_tree_density);
62 m_active_trees = config.Configs["Trees"].GetBoolean("active_trees", m_active_trees);
63 }
64 catch (Exception)
65 {
66 }
67
68 m_trees = new List<UUID>();
69 m_scene = scene;
70
71 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
72
73 if (m_active_trees)
74 activeizeTreeze(true);
75
76 m_log.Debug("[TREES]: Initialised tree module");
77 }
78
79 public void PostInitialise()
80 {
81 }
82
83 public void Close()
84 {
85 }
86
87 public string Name
88 {
89 get { return "TreePopulatorModule"; }
90 }
91
92 public bool IsSharedModule
93 {
94 get { return false; }
95 }
96
97 #endregion
98
99 private void EventManager_OnPluginConsole(string[] args)
100 {
101 if (args.Length == 1)
102 {
103 if (args[0] == "tree")
104 {
105 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
106 if (uuid == UUID.Zero)
107 uuid = m_scene.RegionInfo.MasterAvatarAssignedUUID;
108 m_log.Debug("[TREES]: New tree planting");
109 CreateTree(uuid, new Vector3(128.0f, 128.0f, 0.0f));
110
111 }
112 }
113
114 if (args.Length == 2 || args.Length == 3)
115 {
116 if (args[1] == "active")
117 {
118 if (args.Length >= 3)
119 {
120 if (args[2] == "true" && !m_active_trees)
121 {
122 m_active_trees = true;
123 activeizeTreeze(m_active_trees);
124 m_log.Info("[TREES]: Activizing Trees");
125 }
126 if (args[2] == "false" && m_active_trees)
127 {
128 m_active_trees = false;
129 activeizeTreeze(m_active_trees);
130 m_log.Info("[TREES]: Trees no longer Active, for now...");
131 }
132 }
133 else
134 {
135 m_log.Info("[TREES]: When setting the tree module active via the console, you must specify true or false");
136 }
137 }
138 }
139
140 }
141
142 private void activeizeTreeze(bool activeYN)
143 {
144 if (activeYN)
145 {
146 CalculateTrees = new Timer(m_tree_updates);
147 CalculateTrees.Elapsed += CalculateTrees_Elapsed;
148 CalculateTrees.Start();
149 }
150 else
151 {
152 CalculateTrees.Stop();
153 }
154 }
155
156 private void growTrees()
157 {
158 foreach (UUID tree in m_trees)
159 {
160 if (m_scene.Entities.ContainsKey(tree))
161 {
162 SceneObjectPart s_tree = ((SceneObjectGroup) m_scene.Entities[tree]).RootPart;
163
164 // 100 seconds to grow 1m
165 s_tree.Scale += new Vector3(0.1f, 0.1f, 0.1f);
166 s_tree.SendFullUpdateToAllClients();
167 //s_tree.ScheduleTerseUpdate();
168 }
169 else
170 {
171 m_trees.Remove(tree);
172 }
173 }
174 }
175
176 private void seedTrees()
177 {
178 foreach (UUID tree in m_trees)
179 {
180 if (m_scene.Entities.ContainsKey(tree))
181 {
182 SceneObjectPart s_tree = ((SceneObjectGroup) m_scene.Entities[tree]).RootPart;
183
184 if (s_tree.Scale.X > 0.5)
185 {
186 if (Util.RandomClass.NextDouble() > 0.75)
187 {
188 SpawnChild(s_tree);
189 }
190 }
191 }
192 else
193 {
194 m_trees.Remove(tree);
195 }
196 }
197 }
198
199 private void killTrees()
200 {
201 foreach (UUID tree in m_trees)
202 {
203 double killLikelyhood = 0.0;
204
205 if (m_scene.Entities.ContainsKey(tree))
206 {
207 SceneObjectPart selectedTree = ((SceneObjectGroup) m_scene.Entities[tree]).RootPart;
208 double selectedTreeScale = Math.Sqrt(Math.Pow(selectedTree.Scale.X, 2) +
209 Math.Pow(selectedTree.Scale.Y, 2) +
210 Math.Pow(selectedTree.Scale.Z, 2));
211
212 foreach (UUID picktree in m_trees)
213 {
214 if (picktree != tree)
215 {
216 SceneObjectPart pickedTree = ((SceneObjectGroup) m_scene.Entities[picktree]).RootPart;
217
218 double pickedTreeScale = Math.Sqrt(Math.Pow(pickedTree.Scale.X, 2) +
219 Math.Pow(pickedTree.Scale.Y, 2) +
220 Math.Pow(pickedTree.Scale.Z, 2));
221
222 double pickedTreeDistance = Math.Sqrt(Math.Pow(Math.Abs(pickedTree.AbsolutePosition.X - selectedTree.AbsolutePosition.X), 2) +
223 Math.Pow(Math.Abs(pickedTree.AbsolutePosition.Y - selectedTree.AbsolutePosition.Y), 2) +
224 Math.Pow(Math.Abs(pickedTree.AbsolutePosition.Z - selectedTree.AbsolutePosition.Z), 2));
225
226 killLikelyhood += (selectedTreeScale / (pickedTreeScale * pickedTreeDistance)) * 0.1;
227 }
228 }
229
230 if (Util.RandomClass.NextDouble() < killLikelyhood)
231 {
232 m_scene.DeleteSceneObject(selectedTree.ParentGroup, false);
233 m_trees.Remove(selectedTree.ParentGroup.UUID);
234
235 m_scene.ForEachClient(delegate(IClientAPI controller)
236 {
237 controller.SendKillObject(m_scene.RegionInfo.RegionHandle,
238 selectedTree.LocalId);
239 });
240
241 break;
242 }
243 selectedTree.SetText(killLikelyhood.ToString(), new Vector3(1.0f, 1.0f, 1.0f), 1.0);
244 }
245 else
246 {
247 m_trees.Remove(tree);
248 }
249 }
250 }
251
252 private void SpawnChild(SceneObjectPart s_tree)
253 {
254 Vector3 position = new Vector3();
255
256 position.X = s_tree.AbsolutePosition.X + (1 * (-1 * Util.RandomClass.Next(1)));
257 if (position.X > 255)
258 position.X = 255;
259 if (position.X < 0)
260 position.X = 0;
261 position.Y = s_tree.AbsolutePosition.Y + (1 * (-1 * Util.RandomClass.Next(1)));
262 if (position.Y > 255)
263 position.Y = 255;
264 if (position.Y < 0)
265 position.Y = 0;
266
267 double randX = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3);
268 double randY = ((Util.RandomClass.NextDouble() * 2.0) - 1.0) * (s_tree.Scale.X * 3);
269
270 position.X += (float) randX;
271 position.Y += (float) randY;
272
273 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
274 if (uuid == UUID.Zero)
275 uuid = m_scene.RegionInfo.MasterAvatarAssignedUUID;
276
277 CreateTree(uuid, position);
278 }
279
280 private void CreateTree(UUID uuid, Vector3 position)
281 {
282 position.Z = (float) m_scene.Heightmap[(int) position.X, (int) position.Y];
283
284 IVegetationModule module = m_scene.RequestModuleInterface<IVegetationModule>();
285
286 if (null == module)
287 return;
288
289 SceneObjectGroup tree
290 = module.AddTree(
291 uuid, UUID.Zero, new Vector3(0.1f, 0.1f, 0.1f), Quaternion.Identity, position, Tree.Cypress1, false);
292
293 m_trees.Add(tree.UUID);
294 tree.SendGroupFullUpdate();
295 }
296
297 private void CalculateTrees_Elapsed(object sender, ElapsedEventArgs e)
298 {
299 growTrees();
300 seedTrees();
301 killTrees();
302 }
303 }
304}