OSDN Git Service

Making RadegastInstance public.. also added the GridClient to the constructor
[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 StateManager state;\r
47         private ConfigManager config;\r
48 \r
49         private frmMain mainForm;\r
50         private TabsConsole tabsConsole;\r
51 \r
52         // Singleton, there can be only one instance\r
53         private static RadegastInstance globalInstance = null;\r
54         public static RadegastInstance GlobalInstance\r
55         {\r
56             get\r
57             {\r
58                 if (globalInstance == null)\r
59                 {\r
60                     globalInstance = new RadegastInstance(new GridClient());\r
61                 }\r
62                 return globalInstance;\r
63             }\r
64         }\r
65 \r
66         private string userDir;\r
67         /// <summary>\r
68         /// System (not grid!) user's dir\r
69         /// </summary>\r
70         public string UserDir { get { return userDir; } }\r
71 \r
72         /// <summary>\r
73         /// Grid client's user dir for settings and logs\r
74         /// </summary>\r
75         public string ClientDir\r
76         {\r
77             get\r
78             {\r
79                 if (client != null && client.Self != null && !string.IsNullOrEmpty(client.Self.Name))\r
80                 {\r
81                     return Path.Combine(userDir, client.Self.Name);\r
82                 }\r
83                 else\r
84                 {\r
85                     return Environment.CurrentDirectory;\r
86                 }\r
87             }\r
88         }\r
89 \r
90         public string InventoryCacheFileName { get { return Path.Combine(ClientDir, "inventory.cache"); } }\r
91 \r
92         private string animCacheDir;\r
93         public string AnimCacheDir { get { return animCacheDir; } }\r
94 \r
95         private string globalLogFile;\r
96         public string GlobalLogFile { get { return globalLogFile; } }\r
97 \r
98         private bool monoRuntime;\r
99         public bool MonoRuntime { get { return monoRuntime; } }\r
100 \r
101         private Dictionary<UUID, Group> groups;\r
102         public Dictionary<UUID, Group> Groups { get { return groups; } }\r
103 \r
104         private Settings globalSettings;\r
105         /// <summary>\r
106         /// Global settings for the entire application\r
107         /// </summary>\r
108         public Settings GlobalSettings { get { return globalSettings; } }\r
109 \r
110         private Settings clientSettings;\r
111         /// <summary>\r
112         /// Per client settings\r
113         /// </summary>\r
114         public Settings ClientSettings { get { return clientSettings; } }\r
115 \r
116         public Dictionary<UUID, string> nameCache = new Dictionary<UUID, string>();\r
117 \r
118         public const string INCOMPLETE_NAME = "Loading...";\r
119 \r
120         public readonly bool advancedDebugging = false;\r
121 \r
122         public readonly List<IRadegastPlugin> PluginsLoaded = new List<IRadegastPlugin>();\r
123 \r
124         public RadegastInstance(GridClient client0)\r
125         {\r
126             // incase something else calls GlobalInstance while we are loading\r
127             globalInstance = this; \r
128             InitializeLoggingAndConfig();\r
129 \r
130             client = client0;\r
131 \r
132             client.Settings.MULTIPLE_SIMS = true;\r
133 \r
134             client.Settings.USE_INTERPOLATION_TIMER = false;\r
135             client.Settings.ALWAYS_REQUEST_OBJECTS = true;\r
136             client.Settings.ALWAYS_DECODE_OBJECTS = true;\r
137             client.Settings.OBJECT_TRACKING = true;\r
138             client.Settings.ENABLE_SIMSTATS = true;\r
139             client.Settings.FETCH_MISSING_INVENTORY = true;\r
140             client.Settings.SEND_AGENT_THROTTLE = true;\r
141             client.Settings.SEND_AGENT_UPDATES = true;\r
142 \r
143             client.Settings.USE_ASSET_CACHE = true;\r
144             client.Settings.ASSET_CACHE_DIR = Path.Combine(userDir, "cache");\r
145             client.Assets.Cache.AutoPruneEnabled = false;\r
146 \r
147             client.Throttle.Texture = 2446000.0f;\r
148             client.Throttle.Asset = 2446000.0f;\r
149             client.Settings.THROTTLE_OUTGOING_PACKETS = true;\r
150             client.Settings.LOGIN_TIMEOUT = 120 * 1000;\r
151             client.Settings.SIMULATOR_TIMEOUT = 120 * 1000;\r
152             client.Settings.MAX_CONCURRENT_TEXTURE_DOWNLOADS = 20;\r
153 \r
154             netcom = new RadegastNetcom(client);\r
155             state = new StateManager(this);\r
156 \r
157             InitializeConfigLegacy();\r
158 \r
159             mainForm = new frmMain(this);\r
160             mainForm.InitializeControls();\r
161             tabsConsole = mainForm.TabConsole;\r
162 \r
163             Application.ApplicationExit += new EventHandler(Application_ApplicationExit);\r
164             groups = new Dictionary<UUID, Group>();\r
165 \r
166             client.Groups.OnCurrentGroups += new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);\r
167             client.Groups.OnGroupLeft += new GroupManager.GroupLeftCallback(Groups_OnGroupLeft);\r
168             client.Groups.OnGroupDropped += new GroupManager.GroupDroppedCallback(Groups_OnGroupDropped);\r
169             client.Groups.OnGroupJoined += new GroupManager.GroupJoinedCallback(Groups_OnGroupJoined);\r
170             client.Avatars.OnAvatarNames += new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames);\r
171             client.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnected);\r
172             ScanAndLoadPlugins();\r
173         }\r
174 \r
175         public void CleanUp()\r
176         {\r
177             if (client != null)\r
178             {\r
179                 client.Groups.OnCurrentGroups -= new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);\r
180                 client.Groups.OnGroupLeft -= new GroupManager.GroupLeftCallback(Groups_OnGroupLeft);\r
181                 client.Groups.OnGroupDropped -= new GroupManager.GroupDroppedCallback(Groups_OnGroupDropped);\r
182                 client.Groups.OnGroupJoined -= new GroupManager.GroupJoinedCallback(Groups_OnGroupJoined);\r
183                 client.Avatars.OnAvatarNames -= new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames);\r
184                 client.Network.OnConnected -= new NetworkManager.ConnectedCallback(Network_OnConnected);\r
185             }\r
186 \r
187             lock (PluginsLoaded)\r
188             {\r
189                 PluginsLoaded.ForEach(plug =>\r
190                 {\r
191                     try\r
192                     {\r
193                         plug.StopPlugin(this);\r
194                     }\r
195                     catch (Exception) { }\r
196                 });\r
197             }\r
198 \r
199             state.Dispose();\r
200             state = null;\r
201             netcom.Dispose();\r
202             netcom = null;\r
203             Logger.Log("RadegastInstance finished cleaning up.", Helpers.LogLevel.Debug);\r
204         }\r
205 \r
206         private void ScanAndLoadPlugins()\r
207         {\r
208             string dirName = Application.StartupPath;\r
209 \r
210             if (!Directory.Exists(dirName)) return;\r
211 \r
212             foreach (string loadfilename in Directory.GetFiles(dirName))\r
213             {\r
214                 if (loadfilename.ToLower().EndsWith(".dll") || loadfilename.ToLower().EndsWith(".exe"))\r
215                 {\r
216                     try\r
217                     {\r
218                         Assembly assembly = Assembly.LoadFile(loadfilename);\r
219                         foreach (Type type in assembly.GetTypes())\r
220                         {\r
221                             if (typeof(IRadegastPlugin).IsAssignableFrom(type))\r
222                             {\r
223                                 foreach (var ci in type.GetConstructors())\r
224                                 {\r
225                                     if (ci.GetParameters().Length > 0) continue;\r
226                                     try\r
227                                     {\r
228                                         IRadegastPlugin plug = (IRadegastPlugin)ci.Invoke(new object[0]);\r
229                                         plug.StartPlugin(this);\r
230                                         lock (PluginsLoaded) PluginsLoaded.Add(plug);\r
231                                         break;\r
232                                     }\r
233                                     catch (Exception ex)\r
234                                     {\r
235                                         Logger.Log("ERROR in Radegast Plugin: " + ex.Message, Helpers.LogLevel.Debug);\r
236                                     }\r
237                                 }\r
238                             }\r
239                         }\r
240                     }\r
241                     catch (BadImageFormatException)\r
242                     {\r
243                         // non .NET .dlls\r
244                     }\r
245                     catch (ReflectionTypeLoadException)\r
246                     {\r
247                         // Out of date or dlls missing sub dependencies\r
248                     }\r
249                 }\r
250             }\r
251         }\r
252 \r
253         void Network_OnConnected(object sender)\r
254         {\r
255             try\r
256             {\r
257                 if (!Directory.Exists(ClientDir))\r
258                     Directory.CreateDirectory(ClientDir);\r
259             }\r
260             catch (Exception ex)\r
261             {\r
262                 Logger.Log("Failed to create client directory", Helpers.LogLevel.Warning, ex);\r
263             }\r
264 \r
265             clientSettings = new Settings(Path.Combine(ClientDir, "client_settings.xml"));\r
266         }\r
267 \r
268         void Avatars_OnAvatarNames(Dictionary<UUID, string> names)\r
269         {\r
270             lock (nameCache)\r
271             {\r
272                 foreach (KeyValuePair<UUID, string> av in names)\r
273                 {\r
274                     if (!nameCache.ContainsKey(av.Key))\r
275                     {\r
276                         nameCache.Add(av.Key, av.Value);\r
277                     }\r
278                 }\r
279             }\r
280         }\r
281 \r
282         public string getAvatarName(UUID key)\r
283         {\r
284             lock (nameCache)\r
285             {\r
286                 if (key == UUID.Zero)\r
287                 {\r
288                     return "(???) (???)";\r
289                 }\r
290                 if (nameCache.ContainsKey(key))\r
291                 {\r
292                     return nameCache[key];\r
293                 }\r
294                 else\r
295                 {\r
296                     client.Avatars.RequestAvatarName(key);\r
297                     return INCOMPLETE_NAME;\r
298                 }\r
299             }\r
300         }\r
301 \r
302         public void getAvatarNames(List<UUID> keys)\r
303         {\r
304             lock (nameCache)\r
305             {\r
306                 List<UUID> newNames = new List<UUID>();\r
307                 foreach (UUID key in keys)\r
308                 {\r
309                     if (!nameCache.ContainsKey(key))\r
310                     {\r
311                         newNames.Add(key);\r
312                     }\r
313                 }\r
314                 if (newNames.Count > 0)\r
315                 {\r
316                     client.Avatars.RequestAvatarNames(newNames);\r
317                 }\r
318             }\r
319         }\r
320 \r
321         public bool haveAvatarName(UUID key)\r
322         {\r
323             lock (nameCache)\r
324             {\r
325                 if (nameCache.ContainsKey(key))\r
326                     return true;\r
327                 else\r
328                     return false;\r
329             }\r
330         }\r
331 \r
332         void Groups_OnGroupJoined(UUID groupID, bool success)\r
333         {\r
334             client.Groups.RequestCurrentGroups();\r
335         }\r
336 \r
337         void Groups_OnGroupLeft(UUID groupID, bool success)\r
338         {\r
339             client.Groups.RequestCurrentGroups();\r
340         }\r
341 \r
342         void Groups_OnGroupDropped(UUID groupID)\r
343         {\r
344             client.Groups.RequestCurrentGroups();\r
345         }\r
346 \r
347         public static string SafeFileName(string fileName)\r
348         {\r
349             foreach (char lDisallowed in Path.GetInvalidFileNameChars())\r
350             {\r
351                 fileName = fileName.Replace(lDisallowed.ToString(), "_");\r
352             }\r
353 \r
354             return fileName;\r
355         }\r
356 \r
357         public void LogClientMessage(string fileName, string message)\r
358         {\r
359             lock (this)\r
360             {\r
361                 try\r
362                 {\r
363                     foreach (char lDisallowed in System.IO.Path.GetInvalidFileNameChars())\r
364                     {\r
365                         fileName = fileName.Replace(lDisallowed.ToString(), "_");\r
366                     }\r
367 \r
368                     StreamWriter logfile = File.AppendText(Path.Combine(ClientDir, fileName));\r
369                     logfile.WriteLine(DateTime.Now.ToString("yyyy-MM-dd [HH:mm:ss] ") + message);\r
370                     logfile.Close();\r
371                     logfile.Dispose();\r
372                 }\r
373                 catch (Exception) { }\r
374             }\r
375         }\r
376 \r
377         void Groups_OnCurrentGroups(Dictionary<UUID, Group> gr)\r
378         {\r
379             this.groups = gr;\r
380         }\r
381 \r
382         private void Application_ApplicationExit(object sender, EventArgs e)\r
383         {\r
384             config.SaveCurrentConfig();\r
385         }\r
386 \r
387         private void InitializeLoggingAndConfig()\r
388         {\r
389             // Are we running mono?\r
390             monoRuntime = Type.GetType("Mono.Runtime") != null;\r
391 \r
392             try\r
393             {\r
394                 userDir = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), Properties.Resources.ProgramName);\r
395                 if (!Directory.Exists(userDir))\r
396                 {\r
397                     Directory.CreateDirectory(userDir);\r
398                 }\r
399             }\r
400             catch (Exception)\r
401             {\r
402                 userDir = System.Environment.CurrentDirectory;\r
403             };\r
404 \r
405             animCacheDir = Path.Combine(userDir, @"anim_cache");\r
406             globalLogFile = Path.Combine(userDir, Properties.Resources.ProgramName + ".log");\r
407             globalSettings = new Settings(Path.Combine(userDir, "settings.xml"));\r
408         }\r
409 \r
410         private void InitializeConfigLegacy()\r
411         {\r
412             config = new ConfigManager(this);\r
413             config.ApplyDefault();\r
414 \r
415             netcom.LoginOptions.FirstName = config.CurrentConfig.FirstName;\r
416             netcom.LoginOptions.LastName = config.CurrentConfig.LastName;\r
417             netcom.LoginOptions.Password = config.CurrentConfig.PasswordMD5;\r
418             netcom.LoginOptions.IsPasswordMD5 = true;\r
419         }\r
420 \r
421         public GridClient Client\r
422         {\r
423             get { return client; }\r
424         }\r
425 \r
426         public RadegastNetcom Netcom\r
427         {\r
428             get { return netcom; }\r
429         }\r
430 \r
431         public StateManager State\r
432         {\r
433             get { return state; }\r
434         }\r
435 \r
436         public ConfigManager Config\r
437         {\r
438             get { return config; }\r
439         }\r
440 \r
441         public frmMain MainForm\r
442         {\r
443             get { return mainForm; }\r
444         }\r
445 \r
446         public TabsConsole TabConsole\r
447         {\r
448             get { return tabsConsole; }\r
449         }\r
450     }\r
451 }\r