OSDN Git Service

* Use flicker free ListView
[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();\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         public Dictionary<UUID, string> nameCache = new Dictionary<UUID, string>();\r
105 \r
106         public const string INCOMPLETE_NAME = "Loading...";\r
107 \r
108         public readonly bool advancedDebugging = false;\r
109 \r
110         public readonly List<IRadegastPlugin> PluginsLoaded = new List<IRadegastPlugin>();\r
111 \r
112         private RadegastInstance()\r
113         {\r
114             InitializeLoggingAndConfig();\r
115 \r
116             client = new GridClient();\r
117             client.Settings.USE_INTERPOLATION_TIMER = false;\r
118             client.Settings.ALWAYS_REQUEST_OBJECTS = true;\r
119             client.Settings.ALWAYS_DECODE_OBJECTS = true;\r
120             client.Settings.OBJECT_TRACKING = true;\r
121             client.Settings.ENABLE_SIMSTATS = true;\r
122             client.Settings.FETCH_MISSING_INVENTORY = true;\r
123             client.Settings.MULTIPLE_SIMS = true;\r
124             client.Settings.SEND_AGENT_THROTTLE = true;\r
125             client.Settings.SEND_AGENT_UPDATES = true;\r
126 \r
127             client.Settings.USE_ASSET_CACHE = true;\r
128             client.Settings.ASSET_CACHE_DIR = Path.Combine(userDir, "cache");\r
129             client.Assets.Cache.AutoPruneEnabled = false;\r
130 \r
131             client.Throttle.Texture = 2446000.0f;\r
132             client.Throttle.Asset = 2446000.0f;\r
133             client.Settings.THROTTLE_OUTGOING_PACKETS = true;\r
134             client.Settings.LOGIN_TIMEOUT = 120 * 1000;\r
135             client.Settings.SIMULATOR_TIMEOUT = 120 * 1000;\r
136             client.Settings.MAX_CONCURRENT_TEXTURE_DOWNLOADS = 20;\r
137 \r
138             netcom = new RadegastNetcom(client);\r
139             state = new StateManager(this);\r
140 \r
141             InitializeConfigLegacy();\r
142 \r
143             mainForm = new frmMain(this);\r
144             mainForm.InitializeControls();\r
145             tabsConsole = mainForm.TabConsole;\r
146 \r
147             Application.ApplicationExit += new EventHandler(Application_ApplicationExit);\r
148             groups = new Dictionary<UUID, Group>();\r
149 \r
150             client.Groups.OnCurrentGroups += new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);\r
151             client.Groups.OnGroupLeft += new GroupManager.GroupLeftCallback(Groups_OnGroupLeft);\r
152             client.Groups.OnGroupDropped += new GroupManager.GroupDroppedCallback(Groups_OnGroupDropped);\r
153             client.Groups.OnGroupJoined += new GroupManager.GroupJoinedCallback(Groups_OnGroupJoined);\r
154             client.Avatars.OnAvatarNames += new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames);\r
155             ScanAndLoadPlugins();\r
156         }\r
157 \r
158         private void ScanAndLoadPlugins()\r
159         {\r
160             string dirName = Application.StartupPath;\r
161 \r
162             if (!Directory.Exists(dirName)) return;\r
163 \r
164             foreach (string loadfilename in Directory.GetFiles(dirName))\r
165             {\r
166                 if (loadfilename.ToLower().EndsWith(".dll") || loadfilename.ToLower().EndsWith(".exe"))\r
167                 {\r
168                     try\r
169                     {\r
170                         Assembly assembly = Assembly.LoadFile(loadfilename);\r
171                         foreach (Type type in assembly.GetTypes())\r
172                         {\r
173                             if (typeof(IRadegastPlugin).IsAssignableFrom(type))\r
174                             {\r
175                                 foreach (var ci in type.GetConstructors())\r
176                                 {\r
177                                     if (ci.GetParameters().Length > 0) continue;\r
178                                     try\r
179                                     {\r
180                                         IRadegastPlugin plug = (IRadegastPlugin)ci.Invoke(new object[0]);\r
181                                         plug.StartPlugin(this);\r
182                                         lock (PluginsLoaded) PluginsLoaded.Add(plug);\r
183                                         break;\r
184                                     }\r
185                                     catch (Exception ex)\r
186                                     {\r
187                                         Logger.Log("ERROR in Radegast Plugin: " + ex.Message, Helpers.LogLevel.Debug);\r
188                                     }\r
189                                 }\r
190                             }\r
191                         }\r
192                     }\r
193                     catch (BadImageFormatException)\r
194                     {\r
195                         // non .NET .dlls\r
196                     }\r
197                     catch (ReflectionTypeLoadException)\r
198                     {\r
199                         // Out of date or dlls missing sub dependencies\r
200                     }\r
201                 }\r
202             }\r
203         }\r
204 \r
205         public void CleanUp()\r
206         {\r
207             if (client != null)\r
208             {\r
209                 client.Groups.OnCurrentGroups -= new GroupManager.CurrentGroupsCallback(Groups_OnCurrentGroups);\r
210                 client.Groups.OnGroupLeft -= new GroupManager.GroupLeftCallback(Groups_OnGroupLeft);\r
211                 client.Groups.OnGroupDropped -= new GroupManager.GroupDroppedCallback(Groups_OnGroupDropped);\r
212                 client.Groups.OnGroupJoined -= new GroupManager.GroupJoinedCallback(Groups_OnGroupJoined);\r
213                 client.Avatars.OnAvatarNames -= new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames);\r
214             }\r
215 \r
216             lock (PluginsLoaded)\r
217             {\r
218                 PluginsLoaded.ForEach(plug =>\r
219                                           {\r
220                                               try\r
221                                               {\r
222                                                   plug.StopPlugin(this);\r
223                                               }\r
224                                               catch (Exception) { }\r
225                                           });\r
226             }\r
227 \r
228             state.Dispose();\r
229             state = null;\r
230             netcom.Dispose();\r
231             netcom = null;\r
232             Logger.Log("RadegastInstance finished cleaning up.", Helpers.LogLevel.Debug);\r
233 \r
234             if (monoRuntime)\r
235             {\r
236                 // Force process exit if we're under mono\r
237                 Logger.Log("Exiting...", Helpers.LogLevel.Debug);\r
238                 Environment.Exit(0);\r
239             }\r
240         }\r
241 \r
242         void Avatars_OnAvatarNames(Dictionary<UUID, string> names)\r
243         {\r
244             lock (nameCache)\r
245             {\r
246                 foreach (KeyValuePair<UUID, string> av in names)\r
247                 {\r
248                     if (!nameCache.ContainsKey(av.Key))\r
249                     {\r
250                         nameCache.Add(av.Key, av.Value);\r
251                     }\r
252                 }\r
253             }\r
254         }\r
255 \r
256         public string getAvatarName(UUID key)\r
257         {\r
258             lock (nameCache)\r
259             {\r
260                 if (key == UUID.Zero)\r
261                 {\r
262                     return "(???) (???)";\r
263                 }\r
264                 if (nameCache.ContainsKey(key))\r
265                 {\r
266                     return nameCache[key];\r
267                 }\r
268                 else\r
269                 {\r
270                     client.Avatars.RequestAvatarName(key);\r
271                     return INCOMPLETE_NAME;\r
272                 }\r
273             }\r
274         }\r
275 \r
276         public void getAvatarNames(List<UUID> keys)\r
277         {\r
278             lock (nameCache)\r
279             {\r
280                 List<UUID> newNames = new List<UUID>();\r
281                 foreach (UUID key in keys)\r
282                 {\r
283                     if (!nameCache.ContainsKey(key))\r
284                     {\r
285                         newNames.Add(key);\r
286                     }\r
287                 }\r
288                 if (newNames.Count > 0)\r
289                 {\r
290                     client.Avatars.RequestAvatarNames(newNames);\r
291                 }\r
292             }\r
293         }\r
294 \r
295         public bool haveAvatarName(UUID key)\r
296         {\r
297             lock (nameCache)\r
298             {\r
299                 if (nameCache.ContainsKey(key))\r
300                     return true;\r
301                 else\r
302                     return false;\r
303             }\r
304         }\r
305 \r
306         void Groups_OnGroupJoined(UUID groupID, bool success)\r
307         {\r
308             client.Groups.RequestCurrentGroups();\r
309         }\r
310 \r
311         void Groups_OnGroupLeft(UUID groupID, bool success)\r
312         {\r
313             client.Groups.RequestCurrentGroups();\r
314         }\r
315 \r
316         void Groups_OnGroupDropped(UUID groupID)\r
317         {\r
318             client.Groups.RequestCurrentGroups();\r
319         }\r
320 \r
321         public void LogClientMessage(string fileName, string message)\r
322         {\r
323             lock (this)\r
324             {\r
325                 try\r
326                 {\r
327                     foreach (char lDisallowed in System.IO.Path.GetInvalidFileNameChars())\r
328                     {\r
329                         fileName = fileName.Replace(lDisallowed.ToString(), "_");\r
330                     }\r
331 \r
332                     StreamWriter logfile = File.AppendText(Path.Combine(ClientDir, fileName));\r
333                     logfile.WriteLine(DateTime.Now.ToString("yyyy-MM-dd [HH:mm:ss] ") + message);\r
334                     logfile.Close();\r
335                     logfile.Dispose();\r
336                 }\r
337                 catch (Exception) { }\r
338             }\r
339         }\r
340 \r
341         void Groups_OnCurrentGroups(Dictionary<UUID, Group> gr)\r
342         {\r
343             this.groups = gr;\r
344         }\r
345 \r
346         private void Application_ApplicationExit(object sender, EventArgs e)\r
347         {\r
348             config.SaveCurrentConfig();\r
349         }\r
350 \r
351         private void InitializeLoggingAndConfig()\r
352         {\r
353             // Are we running mono?\r
354             monoRuntime == Type.GetType("Mono.Runtime") != null;\r
355 \r
356             try\r
357             {\r
358                 userDir = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), Properties.Resources.ProgramName);\r
359                 if (!Directory.Exists(userDir))\r
360                 {\r
361                     Directory.CreateDirectory(userDir);\r
362                 }\r
363             }\r
364             catch (Exception)\r
365             {\r
366                 userDir = System.Environment.CurrentDirectory;\r
367             };\r
368 \r
369             animCacheDir = Path.Combine(userDir, @"anim_cache");\r
370             globalLogFile = Path.Combine(userDir, Properties.Resources.ProgramName + ".log");\r
371         }\r
372 \r
373         private void InitializeConfigLegacy()\r
374         {\r
375             config = new ConfigManager(this);\r
376             config.ApplyDefault();\r
377 \r
378             netcom.LoginOptions.FirstName = config.CurrentConfig.FirstName;\r
379             netcom.LoginOptions.LastName = config.CurrentConfig.LastName;\r
380             netcom.LoginOptions.Password = config.CurrentConfig.PasswordMD5;\r
381             netcom.LoginOptions.IsPasswordMD5 = true;\r
382         }\r
383 \r
384         public GridClient Client\r
385         {\r
386             get { return client; }\r
387         }\r
388 \r
389         public RadegastNetcom Netcom\r
390         {\r
391             get { return netcom; }\r
392         }\r
393 \r
394         public StateManager State\r
395         {\r
396             get { return state; }\r
397         }\r
398 \r
399         public ConfigManager Config\r
400         {\r
401             get { return config; }\r
402         }\r
403 \r
404         public frmMain MainForm\r
405         {\r
406             get { return mainForm; }\r
407         }\r
408 \r
409         public TabsConsole TabConsole\r
410         {\r
411             get { return tabsConsole; }\r
412         }\r
413     }\r
414 }\r