2 // Radegast Metaverse Client
\r
3 // Copyright (c) 2009, Radegast Development Team
\r
4 // All rights reserved.
\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
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
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
32 using System.Collections.Generic;
\r
34 using System.Reflection;
\r
35 using System.Windows.Forms;
\r
36 using Radegast.Netcom;
\r
37 using OpenMetaverse;
\r
41 public class RadegastInstance
\r
43 private GridClient client;
\r
44 private RadegastNetcom netcom;
\r
46 private StateManager state;
\r
47 private ConfigManager config;
\r
49 private frmMain mainForm;
\r
50 private TabsConsole tabsConsole;
\r
52 // Singleton, there can be only one instance
\r
53 private static RadegastInstance globalInstance = null;
\r
54 public static RadegastInstance GlobalInstance
\r
58 if (globalInstance == null)
\r
60 globalInstance = new RadegastInstance(new GridClient());
\r
62 return globalInstance;
\r
66 private string userDir;
\r
68 /// System (not grid!) user's dir
\r
70 public string UserDir { get { return userDir; } }
\r
73 /// Grid client's user dir for settings and logs
\r
75 public string ClientDir
\r
79 if (client != null && client.Self != null && !string.IsNullOrEmpty(client.Self.Name))
\r
81 return Path.Combine(userDir, client.Self.Name);
\r
85 return Environment.CurrentDirectory;
\r
90 public string InventoryCacheFileName { get { return Path.Combine(ClientDir, "inventory.cache"); } }
\r
92 private string animCacheDir;
\r
93 public string AnimCacheDir { get { return animCacheDir; } }
\r
95 private string globalLogFile;
\r
96 public string GlobalLogFile { get { return globalLogFile; } }
\r
98 private bool monoRuntime;
\r
99 public bool MonoRuntime { get { return monoRuntime; } }
\r
101 private Dictionary<UUID, Group> groups;
\r
102 public Dictionary<UUID, Group> Groups { get { return groups; } }
\r
104 private Settings globalSettings;
\r
106 /// Global settings for the entire application
\r
108 public Settings GlobalSettings { get { return globalSettings; } }
\r
110 private Settings clientSettings;
\r
112 /// Per client settings
\r
114 public Settings ClientSettings { get { return clientSettings; } }
\r
116 public Dictionary<UUID, string> nameCache = new Dictionary<UUID, string>();
\r
118 public const string INCOMPLETE_NAME = "Loading...";
\r
120 public readonly bool advancedDebugging = false;
\r
122 public readonly List<IRadegastPlugin> PluginsLoaded = new List<IRadegastPlugin>();
\r
124 public RadegastInstance(GridClient client0)
\r
126 // incase something else calls GlobalInstance while we are loading
\r
127 globalInstance = this;
\r
128 InitializeLoggingAndConfig();
\r
132 client.Settings.MULTIPLE_SIMS = true;
\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
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
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
154 netcom = new RadegastNetcom(client);
\r
155 state = new StateManager(this);
\r
157 InitializeConfigLegacy();
\r
159 mainForm = new frmMain(this);
\r
160 mainForm.InitializeControls();
\r
161 tabsConsole = mainForm.TabConsole;
\r
163 Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
\r
164 groups = new Dictionary<UUID, Group>();
\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
175 public void CleanUp()
\r
177 if (client != null)
\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
187 lock (PluginsLoaded)
\r
189 PluginsLoaded.ForEach(plug =>
\r
193 plug.StopPlugin(this);
\r
195 catch (Exception) { }
\r
203 Logger.Log("RadegastInstance finished cleaning up.", Helpers.LogLevel.Debug);
\r
206 private void ScanAndLoadPlugins()
\r
208 string dirName = Application.StartupPath;
\r
210 if (!Directory.Exists(dirName)) return;
\r
212 foreach (string loadfilename in Directory.GetFiles(dirName))
\r
214 if (loadfilename.ToLower().EndsWith(".dll") || loadfilename.ToLower().EndsWith(".exe"))
\r
218 Assembly assembly = Assembly.LoadFile(loadfilename);
\r
219 foreach (Type type in assembly.GetTypes())
\r
221 if (typeof(IRadegastPlugin).IsAssignableFrom(type))
\r
223 foreach (var ci in type.GetConstructors())
\r
225 if (ci.GetParameters().Length > 0) continue;
\r
228 IRadegastPlugin plug = (IRadegastPlugin)ci.Invoke(new object[0]);
\r
229 plug.StartPlugin(this);
\r
230 lock (PluginsLoaded) PluginsLoaded.Add(plug);
\r
233 catch (Exception ex)
\r
235 Logger.Log("ERROR in Radegast Plugin: " + ex.Message, Helpers.LogLevel.Debug);
\r
241 catch (BadImageFormatException)
\r
245 catch (ReflectionTypeLoadException)
\r
247 // Out of date or dlls missing sub dependencies
\r
253 void Network_OnConnected(object sender)
\r
257 if (!Directory.Exists(ClientDir))
\r
258 Directory.CreateDirectory(ClientDir);
\r
260 catch (Exception ex)
\r
262 Logger.Log("Failed to create client directory", Helpers.LogLevel.Warning, ex);
\r
265 clientSettings = new Settings(Path.Combine(ClientDir, "client_settings.xml"));
\r
268 void Avatars_OnAvatarNames(Dictionary<UUID, string> names)
\r
272 foreach (KeyValuePair<UUID, string> av in names)
\r
274 if (!nameCache.ContainsKey(av.Key))
\r
276 nameCache.Add(av.Key, av.Value);
\r
282 public string getAvatarName(UUID key)
\r
286 if (key == UUID.Zero)
\r
288 return "(???) (???)";
\r
290 if (nameCache.ContainsKey(key))
\r
292 return nameCache[key];
\r
296 client.Avatars.RequestAvatarName(key);
\r
297 return INCOMPLETE_NAME;
\r
302 public void getAvatarNames(List<UUID> keys)
\r
306 List<UUID> newNames = new List<UUID>();
\r
307 foreach (UUID key in keys)
\r
309 if (!nameCache.ContainsKey(key))
\r
314 if (newNames.Count > 0)
\r
316 client.Avatars.RequestAvatarNames(newNames);
\r
321 public bool haveAvatarName(UUID key)
\r
325 if (nameCache.ContainsKey(key))
\r
332 void Groups_OnGroupJoined(UUID groupID, bool success)
\r
334 client.Groups.RequestCurrentGroups();
\r
337 void Groups_OnGroupLeft(UUID groupID, bool success)
\r
339 client.Groups.RequestCurrentGroups();
\r
342 void Groups_OnGroupDropped(UUID groupID)
\r
344 client.Groups.RequestCurrentGroups();
\r
347 public static string SafeFileName(string fileName)
\r
349 foreach (char lDisallowed in Path.GetInvalidFileNameChars())
\r
351 fileName = fileName.Replace(lDisallowed.ToString(), "_");
\r
357 public void LogClientMessage(string fileName, string message)
\r
363 foreach (char lDisallowed in System.IO.Path.GetInvalidFileNameChars())
\r
365 fileName = fileName.Replace(lDisallowed.ToString(), "_");
\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
373 catch (Exception) { }
\r
377 void Groups_OnCurrentGroups(Dictionary<UUID, Group> gr)
\r
382 private void Application_ApplicationExit(object sender, EventArgs e)
\r
384 config.SaveCurrentConfig();
\r
387 private void InitializeLoggingAndConfig()
\r
389 // Are we running mono?
\r
390 monoRuntime = Type.GetType("Mono.Runtime") != null;
\r
394 userDir = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), Properties.Resources.ProgramName);
\r
395 if (!Directory.Exists(userDir))
\r
397 Directory.CreateDirectory(userDir);
\r
402 userDir = System.Environment.CurrentDirectory;
\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
410 private void InitializeConfigLegacy()
\r
412 config = new ConfigManager(this);
\r
413 config.ApplyDefault();
\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
421 public GridClient Client
\r
423 get { return client; }
\r
426 public RadegastNetcom Netcom
\r
428 get { return netcom; }
\r
431 public StateManager State
\r
433 get { return state; }
\r
436 public ConfigManager Config
\r
438 get { return config; }
\r
441 public frmMain MainForm
\r
443 get { return mainForm; }
\r
446 public TabsConsole TabConsole
\r
448 get { return tabsConsole; }
\r