OSDN Git Service

Update to current libomv trunk (0.8-dev)
[radegast/radegast.git] / Radegast / Core / RadegastInstance.cs
1 // \r
2 // Radegast Metaverse Client\r
3 // Copyright (c) 2009, Radegast Development Team\r
4 // All rights reserved.\r
5 // \r
6 // Redistribution and use in source and binary forms, with or without\r
7 // modification, are permitted provided that the following conditions are met:\r
8 // \r
9 //     * Redistributions of source code must retain the above copyright notice,\r
10 //       this list of conditions and the following disclaimer.\r
11 //     * Redistributions in binary form must reproduce the above copyright\r
12 //       notice, this list of conditions and the following disclaimer in the\r
13 //       documentation and/or other materials provided with the distribution.\r
14 //     * Neither the name of the application "Radegast", nor the names of its\r
15 //       contributors may be used to endorse or promote products derived from\r
16 //       this software without specific prior written permission.\r
17 // \r
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
28 //\r
29 // $Id$\r
30 //\r
31 using System;\r
32 using System.Collections.Generic;\r
33 using System.IO;\r
34 using System.Reflection;\r
35 using System.Windows.Forms;\r
36 using Radegast.Netcom;\r
37 using OpenMetaverse;\r
38 \r
39 namespace Radegast\r
40 {\r
41     public class RadegastInstance\r
42     {\r
43         private GridClient client;\r
44         private RadegastNetcom netcom;\r
45 \r
46         private ImageCache imageCache;\r
47         private StateManager state;\r
48         private ConfigManager config;\r
49 \r
50         private frmMain mainForm;\r
51         private TabsConsole tabsConsole;\r
52 \r
53         // Singleton, there can be only one instance\r
54         private static RadegastInstance globalInstance = null;\r
55         public static RadegastInstance GlobalInstance\r
56         {\r
57             get\r
58             {\r
59                 if (globalInstance == null)\r
60                 {\r
61                     globalInstance = new RadegastInstance();\r
62                 }\r
63                 return globalInstance;\r
64             }\r
65         }\r
66 \r
67         private string userDir;\r
68         /// <summary>\r
69         /// System (not grid!) user's dir\r
70         /// </summary>\r
71         public string UserDir { get { return userDir; } }\r
72 \r
73         /// <summary>\r
74         /// Grid client's user dir for settings and logs\r
75         /// </summary>\r
76         public string ClientDir\r
77         {\r
78             get\r
79             {\r
80                 if (client != null && client.Self != null && !string.IsNullOrEmpty(client.Self.Name))\r
81                 {\r
82                     return Path.Combine(userDir, client.Self.Name);\r
83                 }\r
84                 else\r
85                 {\r
86                     return Environment.CurrentDirectory;\r
87                 }\r
88             }\r
89         }\r
90 \r
91         public string InventoryCacheFileName { get { return Path.Combine(ClientDir, "inventory.cache"); } }\r
92 \r
93         private string animCacheDir;\r
94         public string AnimCacheDir { get { return animCacheDir; } }\r
95 \r
96         private string globalLogFile;\r
97         public string GlobalLogFile { get { return globalLogFile; } }\r
98 \r
99         private bool monoRuntime;\r
100         public bool MonoRuntime { get { return monoRuntime; } }\r
101 \r
102         private Dictionary<UUID, Group> groups;\r
103         public Dictionary<UUID, Group> Groups { get { return groups; } }\r
104 \r
105         public Dictionary<UUID, string> nameCache = new Dictionary<UUID, string>();\r
106 \r
107         public const string INCOMPLETE_NAME = "Loading...";\r
108 \r
109         public readonly bool advancedDebugging = false;\r
110 \r
111         public readonly List<IRadegastPlugin> PluginsLoaded = new List<IRadegastPlugin>();\r
112 \r
113         private RadegastInstance()\r
114         {\r
115             InitializeLoggingAndConfig();\r
116 \r
117             client = new GridClient();\r
118             client.Settings.USE_INTERPOLATION_TIMER = false;\r
119             client.Settings.ALWAYS_REQUEST_OBJECTS = true;\r
120             client.Settings.ALWAYS_DECODE_OBJECTS = true;\r
121             client.Settings.OBJECT_TRACKING = true;\r
122             client.Settings.ENABLE_SIMSTATS = true;\r
123             client.Settings.FETCH_MISSING_INVENTORY = true;\r
124             client.Settings.MULTIPLE_SIMS = true;\r
125             client.Settings.SEND_AGENT_THROTTLE = true;\r
126             client.Settings.SEND_AGENT_UPDATES = true;\r
127 \r
128             client.Settings.USE_ASSET_CACHE = true;\r
129             client.Settings.ASSET_CACHE_DIR = Path.Combine(userDir, "cache");\r
130             client.Assets.Cache.AutoPruneEnabled = false;\r
131 \r
132             client.Throttle.Texture = 2446000.0f;\r
133             client.Throttle.Asset = 2446000.0f;\r
134             client.Settings.THROTTLE_OUTGOING_PACKETS = true;\r
135             client.Settings.LOGIN_TIMEOUT = 120 * 1000;\r
136             client.Settings.SIMULATOR_TIMEOUT = 120 * 1000;\r
137             client.Settings.MAX_CONCURRENT_TEXTURE_DOWNLOADS = 20;\r
138 \r
139             netcom = new RadegastNetcom(client);\r
140             imageCache = new ImageCache();\r
141             state = new StateManager(this);\r
142 \r
143             InitializeConfigLegacy();\r
144 \r
145             mainForm = new frmMain(this);\r
146             mainForm.InitializeControls();\r
147             tabsConsole = mainForm.TabConsole;\r
148 \r
149             Application.ApplicationExit += new EventHandler(Application_ApplicationExit);\r
150             groups = new Dictionary<UUID, Group>();\r
151 \r
152             client.Groups.OnCurrentGroups += new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);\r
153             client.Groups.OnGroupLeft += new GroupManager.GroupLeftCallback(Groups_OnGroupLeft);\r
154             client.Groups.OnGroupDropped += new GroupManager.GroupDroppedCallback(Groups_OnGroupDropped);\r
155             client.Groups.OnGroupJoined += new GroupManager.GroupJoinedCallback(Groups_OnGroupJoined);\r
156             client.Avatars.OnAvatarNames += new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames);\r
157             ScanAndLoadPlugins();\r
158         }\r
159 \r
160         private void ScanAndLoadPlugins()\r
161         {\r
162             string dirName = Application.StartupPath;\r
163 \r
164             if (!Directory.Exists(dirName)) return;\r
165 \r
166             foreach (string loadfilename in Directory.GetFiles(dirName))\r
167             {\r
168                 if (loadfilename.ToLower().EndsWith(".dll") || loadfilename.ToLower().EndsWith(".exe"))\r
169                 {\r
170                     try\r
171                     {\r
172                         Assembly assembly = Assembly.LoadFile(loadfilename);\r
173                         foreach (Type type in assembly.GetTypes())\r
174                         {\r
175                             if (typeof(IRadegastPlugin).IsAssignableFrom(type))\r
176                             {\r
177                                 foreach (var ci in type.GetConstructors())\r
178                                 {\r
179                                     if (ci.GetParameters().Length > 0) continue;\r
180                                     try\r
181                                     {\r
182                                         IRadegastPlugin plug = (IRadegastPlugin)ci.Invoke(new object[0]);\r
183                                         plug.StartPlugin(this);\r
184                                         lock (PluginsLoaded) PluginsLoaded.Add(plug);\r
185                                         break;\r
186                                     }\r
187                                     catch (Exception ex)\r
188                                     {\r
189                                         Logger.Log("ERROR in Radegast Plugin: " + ex.Message, Helpers.LogLevel.Debug);\r
190                                     }\r
191                                 }\r
192                             }\r
193                         }\r
194                     }\r
195                     catch (BadImageFormatException)\r
196                     {\r
197                         // non .NET .dlls\r
198                     }\r
199                     catch (ReflectionTypeLoadException)\r
200                     {\r
201                         // Out of date or dlls missing sub dependencies\r
202                     }\r
203                 }\r
204             }\r
205         }\r
206 \r
207         public void CleanUp()\r
208         {\r
209             if (client != null)\r
210             {\r
211                 client.Groups.OnCurrentGroups -= new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);\r
212                 client.Groups.OnGroupLeft -= new GroupManager.GroupLeftCallback(Groups_OnGroupLeft);\r
213                 client.Groups.OnGroupDropped -= new GroupManager.GroupDroppedCallback(Groups_OnGroupDropped);\r
214                 client.Groups.OnGroupJoined -= new GroupManager.GroupJoinedCallback(Groups_OnGroupJoined);\r
215                 client.Avatars.OnAvatarNames -= new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames);\r
216             }\r
217             \r
218             lock (PluginsLoaded)\r
219             {\r
220                 PluginsLoaded.ForEach(plug =>\r
221                                           {\r
222                                               try\r
223                                               {\r
224                                                   plug.StopPlugin(this);\r
225                                               }\r
226                                               catch (Exception) { }\r
227                                           });\r
228             }\r
229 \r
230             state.Dispose();\r
231             state = null;\r
232             netcom.Dispose();\r
233             netcom = null;\r
234             Logger.Log("RadegastInstance finished cleaning up.", Helpers.LogLevel.Debug);\r
235 \r
236             if (monoRuntime)\r
237             {\r
238                 // Force process exit if we're under mono\r
239                 Logger.Log("Exiting...", Helpers.LogLevel.Debug);\r
240                 Environment.Exit(0);\r
241             }\r
242         }\r
243 \r
244         void Avatars_OnAvatarNames(Dictionary<UUID, string> names)\r
245         {\r
246             lock (nameCache)\r
247             {\r
248                 foreach (KeyValuePair<UUID, string> av in names)\r
249                 {\r
250                     if (!nameCache.ContainsKey(av.Key))\r
251                     {\r
252                         nameCache.Add(av.Key, av.Value);\r
253                     }\r
254                 }\r
255             }\r
256         }\r
257 \r
258         public string getAvatarName(UUID key)\r
259         {\r
260             lock (nameCache)\r
261             {\r
262                 if (key == UUID.Zero)\r
263                 {\r
264                     return "(???) (???)";\r
265                 }\r
266                 if (nameCache.ContainsKey(key))\r
267                 {\r
268                     return nameCache[key];\r
269                 }\r
270                 else\r
271                 {\r
272                     client.Avatars.RequestAvatarName(key);\r
273                     return INCOMPLETE_NAME;\r
274                 }\r
275             }\r
276         }\r
277 \r
278         public void getAvatarNames(List<UUID> keys)\r
279         {\r
280             lock (nameCache)\r
281             {\r
282                 List<UUID> newNames = new List<UUID>();\r
283                 foreach (UUID key in keys)\r
284                 {\r
285                     if (!nameCache.ContainsKey(key))\r
286                     {\r
287                         newNames.Add(key);\r
288                     }\r
289                 }\r
290                 if (newNames.Count > 0)\r
291                 {\r
292                     client.Avatars.RequestAvatarNames(newNames);\r
293                 }\r
294             }\r
295         }\r
296 \r
297         public bool haveAvatarName(UUID key)\r
298         {\r
299             lock (nameCache)\r
300             {\r
301                 if (nameCache.ContainsKey(key))\r
302                     return true;\r
303                 else\r
304                     return false;\r
305             }\r
306         }\r
307 \r
308         void Groups_OnGroupJoined(UUID groupID, bool success)\r
309         {\r
310             client.Groups.RequestCurrentGroups();\r
311         }\r
312 \r
313         void Groups_OnGroupLeft(UUID groupID, bool success)\r
314         {\r
315             client.Groups.RequestCurrentGroups();\r
316         }\r
317 \r
318         void Groups_OnGroupDropped(UUID groupID)\r
319         {\r
320             client.Groups.RequestCurrentGroups();\r
321         }\r
322 \r
323         public void LogClientMessage(string fileName, string message)\r
324         {\r
325             lock (this)\r
326             {\r
327                 try\r
328                 {\r
329                     foreach (char lDisallowed in System.IO.Path.GetInvalidFileNameChars())\r
330                     {\r
331                         fileName = fileName.Replace(lDisallowed.ToString(), "_");\r
332                     }\r
333 \r
334                     StreamWriter logfile = File.AppendText(Path.Combine(ClientDir, fileName));\r
335                     logfile.WriteLine(DateTime.Now.ToString("yyyy-MM-dd [HH:mm:ss] ") + message);\r
336                     logfile.Close();\r
337                     logfile.Dispose();\r
338                 }\r
339                 catch (Exception) { }\r
340             }\r
341         }\r
342 \r
343         void Groups_OnCurrentGroups(Dictionary<UUID, Group> gr)\r
344         {\r
345             this.groups = gr;\r
346         }\r
347 \r
348         private void Application_ApplicationExit(object sender, EventArgs e)\r
349         {\r
350             config.SaveCurrentConfig();\r
351         }\r
352 \r
353         private void InitializeLoggingAndConfig()\r
354         {\r
355             // Are we running mono?\r
356             if (null == Type.GetType("Mono.Runtime"))\r
357             {\r
358                 monoRuntime = false;\r
359             }\r
360             else\r
361             {\r
362                 monoRuntime = true;\r
363             }\r
364 \r
365             try\r
366             {\r
367                 userDir = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), Properties.Resources.ProgramName);\r
368                 if (!Directory.Exists(userDir))\r
369                 {\r
370                     Directory.CreateDirectory(userDir);\r
371                 }\r
372             }\r
373             catch (Exception)\r
374             {\r
375                 userDir = System.Environment.CurrentDirectory;\r
376             };\r
377 \r
378             animCacheDir = Path.Combine(userDir, @"anim_cache");\r
379             globalLogFile = Path.Combine(userDir, Properties.Resources.ProgramName + ".log");\r
380         }\r
381 \r
382         private void InitializeConfigLegacy()\r
383         {\r
384             config = new ConfigManager(this);\r
385             config.ApplyDefault();\r
386 \r
387             netcom.LoginOptions.FirstName = config.CurrentConfig.FirstName;\r
388             netcom.LoginOptions.LastName = config.CurrentConfig.LastName;\r
389             netcom.LoginOptions.Password = config.CurrentConfig.PasswordMD5;\r
390             netcom.LoginOptions.IsPasswordMD5 = true;\r
391         }\r
392 \r
393         public GridClient Client\r
394         {\r
395             get { return client; }\r
396         }\r
397 \r
398         public RadegastNetcom Netcom\r
399         {\r
400             get { return netcom; }\r
401         }\r
402 \r
403         public ImageCache ImageCache\r
404         {\r
405             get { return imageCache; }\r
406         }\r
407 \r
408         public StateManager State\r
409         {\r
410             get { return state; }\r
411         }\r
412 \r
413         public ConfigManager Config\r
414         {\r
415             get { return config; }\r
416         }\r
417 \r
418         public frmMain MainForm\r
419         {\r
420             get { return mainForm; }\r
421         }\r
422 \r
423         public TabsConsole TabConsole\r
424         {\r
425             get { return tabsConsole; }\r
426         }\r
427     }\r
428 }\r