mirror of
https://github.com/RaindropViewer/RaindropViewer.git
synced 2026-07-31 03:22:14 +00:00
856 lines
29 KiB
C#
856 lines
29 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
using Disk;
|
|
//using Radegast.Commands;
|
|
using Raindrop.Netcom;
|
|
using Raindrop.Media;
|
|
using Raindrop.UI.Notification;
|
|
using OpenMetaverse;
|
|
using Plugins.CommonDependencies;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using Logger = OpenMetaverse.Logger;
|
|
|
|
namespace Raindrop
|
|
{
|
|
// The singleton instance of the game client.
|
|
public class RaindropInstance
|
|
{
|
|
// Singleton, there can be only one instance
|
|
private static RaindropInstance globalInstance = null;
|
|
public static RaindropInstance GlobalInstance =>
|
|
globalInstance ??= new RaindropInstance(new GridClient());
|
|
|
|
private GridClient _client; //backend monolith API
|
|
private RaindropNetcom _netcom;
|
|
|
|
private StateManager _state;
|
|
|
|
// managed the chats that are loaded in memory. (including local chat.)
|
|
// public ChatManager ChatManger { get { return chatManger; } }
|
|
// private ChatManager chatManger;
|
|
|
|
/// <summary>
|
|
/// Manages retrieving avatar names
|
|
/// </summary>
|
|
public NameManager Names { get { return _names; } }
|
|
private NameManager _names;
|
|
|
|
/// <summary>
|
|
/// When was Radegast started (UTC)
|
|
/// </summary>
|
|
public readonly DateTime StartupTimeUtc;
|
|
|
|
/// <summary>
|
|
/// Time zone of the current world (currently hard coded to US Pacific time)
|
|
/// </summary>
|
|
public TimeZoneInfo WordTimeZone;
|
|
|
|
/// <summary>
|
|
/// System (not grid!) user's dir
|
|
/// </summary>
|
|
public string UserDir { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Grid client's user dir for settings and logs
|
|
/// ala the path combined with the account's full name
|
|
/// </summary>
|
|
public string ClientDir
|
|
{
|
|
get
|
|
{
|
|
if (_client != null && _client.Self != null && !string.IsNullOrEmpty(_client.Self.Name))
|
|
{
|
|
return Path.Combine(UserDir, _client.Self.Name);
|
|
}
|
|
else
|
|
{
|
|
return Environment.CurrentDirectory;
|
|
}
|
|
}
|
|
}
|
|
|
|
public string InventoryCacheFileName { get { return Path.Combine(ClientDir, "inventory.cache"); } }
|
|
|
|
private string _globalLogFile;
|
|
public string GlobalLogFile { get { return _globalLogFile; } }
|
|
|
|
private bool _monoRuntime;
|
|
public bool MonoRuntime { get { return _monoRuntime; } }
|
|
|
|
public Dictionary<UUID, Group> Groups { get; private set; } = new Dictionary<UUID, Group>();
|
|
|
|
private Settings _globalSettings;
|
|
/// <summary>
|
|
/// Global settings for the entire application
|
|
/// </summary>
|
|
public Settings GlobalSettings { get { return _globalSettings; } }
|
|
|
|
/// <summary>
|
|
/// Per client settings
|
|
/// </summary>
|
|
public Settings ClientSettings { get; private set; }
|
|
|
|
public const string IncompleteName = "Loading...";
|
|
|
|
public readonly bool AdvancedDebugging = false;
|
|
|
|
//private PluginManager pluginManager;
|
|
///// <summary> Handles loading plugins and scripts</summary>
|
|
//public PluginManager PluginManager { get { return pluginManager; } }
|
|
|
|
/// <summary>
|
|
/// Radegast media manager for playing streams and in world sounds
|
|
/// </summary>
|
|
public MediaManager MediaManager { get; private set; }
|
|
|
|
|
|
//private CommandsManager commandsManager;
|
|
///// <summary>
|
|
///// Radegast command manager for executing textual console commands
|
|
///// </summary>
|
|
//public CommandsManager CommandsManager { get { return commandsManager; } }
|
|
|
|
/// <summary>
|
|
/// Radegast ContextAction manager for context sensitive actions
|
|
/// </summary>
|
|
//public ContextActionsManager ContextActionManager { get; private set; }
|
|
|
|
private RaindropMovement _movement;
|
|
/// <summary>
|
|
/// Allows key emulation for moving avatar around
|
|
/// </summary>
|
|
public RaindropMovement Movement { get { return _movement; } }
|
|
|
|
//private InventoryClipboard inventoryClipboard;
|
|
///// <summary>
|
|
///// The last item that was cut or copied in the inventory, used for pasting
|
|
///// in a different place on the inventory, or other places like profile
|
|
///// that allow sending copied inventory items
|
|
///// </summary>
|
|
//public InventoryClipboard InventoryClipboard
|
|
//{
|
|
// get { return inventoryClipboard; }
|
|
// set
|
|
// {
|
|
// inventoryClipboard = value;
|
|
// OnInventoryClipboardUpdated(EventArgs.Empty);
|
|
// }
|
|
//}
|
|
|
|
//private RLVManager rlv;
|
|
|
|
///// <summary>
|
|
///// Manager for RLV functionality
|
|
///// </summary>
|
|
//public RLVManager RLV { get { return rlv; } }
|
|
|
|
private GridManager _gridManager;
|
|
/// <summary>Manages default params for different grids</summary>
|
|
public GridManager GridManger { get { return _gridManager; } }
|
|
|
|
|
|
/// <summary>
|
|
/// Current Outfit Folder (appearnce) manager
|
|
/// </summary>
|
|
public CurrentOutfitFolder Cof;
|
|
|
|
/// <summary>
|
|
/// Did we report crash to the grid login service
|
|
/// </summary>
|
|
public bool ReportedCrash = false;
|
|
|
|
private string CrashMarkerFileName
|
|
{
|
|
get
|
|
{
|
|
return Path.Combine(UserDir, "crash_marker");
|
|
}
|
|
}
|
|
|
|
#region Events
|
|
|
|
#region ClientChanged event
|
|
/// <summary>The event subscribers, null of no subscribers</summary>
|
|
private EventHandler<ClientChangedEventArgs> _mClientChanged;
|
|
|
|
///<summary>Raises the ClientChanged Event</summary>
|
|
/// <param name="e">A ClientChangedEventArgs object containing
|
|
/// the old and the new client</param>
|
|
protected virtual void OnClientChanged(ClientChangedEventArgs e)
|
|
{
|
|
EventHandler<ClientChangedEventArgs> handler = _mClientChanged;
|
|
if (handler != null)
|
|
handler(this, e);
|
|
}
|
|
|
|
/// <summary>Thread sync lock object</summary>
|
|
private readonly object _mClientChangedLock = new object();
|
|
|
|
/// <summary>Raised when the GridClient object in the main Radegast instance is changed</summary>
|
|
public event EventHandler<ClientChangedEventArgs> ClientChanged
|
|
{
|
|
add { lock (_mClientChangedLock) { _mClientChanged += value; } }
|
|
remove { lock (_mClientChangedLock) { _mClientChanged -= value; } }
|
|
}
|
|
#endregion ClientChanged event
|
|
|
|
#region InventoryClipboardUpdated event
|
|
/// <summary>The event subscribers, null of no subscribers</summary>
|
|
private EventHandler<EventArgs> _mInventoryClipboardUpdated;
|
|
|
|
///<summary>Raises the InventoryClipboardUpdated Event</summary>
|
|
/// <param name="e">A EventArgs object containing
|
|
/// the old and the new client</param>
|
|
protected virtual void OnInventoryClipboardUpdated(EventArgs e)
|
|
{
|
|
EventHandler<EventArgs> handler = _mInventoryClipboardUpdated;
|
|
if (handler != null)
|
|
handler(this, e);
|
|
}
|
|
|
|
/// <summary>Thread sync lock object</summary>
|
|
private readonly object _mInventoryClipboardUpdatedLock = new object();
|
|
|
|
/// <summary>Raised when the GridClient object in the main Radegast instance is changed</summary>
|
|
public event EventHandler<EventArgs> InventoryClipboardUpdated
|
|
{
|
|
add { lock (_mInventoryClipboardUpdatedLock) { _mInventoryClipboardUpdated += value; } }
|
|
remove { lock (_mInventoryClipboardUpdatedLock) { _mInventoryClipboardUpdated -= value; } }
|
|
}
|
|
#endregion InventoryClipboardUpdated event
|
|
|
|
|
|
#endregion Events
|
|
|
|
public RaindropInstance(GridClient client)
|
|
{
|
|
InitializeLoggingAndConfigAndUserDirectory();
|
|
|
|
_client = client;
|
|
|
|
// Initialize current time zone, and mark when we started
|
|
GetWorldTimeZone();
|
|
StartupTimeUtc = DateTime.UtcNow;
|
|
|
|
// Are we running mono?
|
|
_monoRuntime = Type.GetType("Mono.Runtime") != null;
|
|
if (_monoRuntime)
|
|
{
|
|
Logger.Log("Mono runtime is detected. This should not happen except in the editor.", Helpers.LogLevel.Warning);
|
|
}
|
|
|
|
//init client file paths, client settings, and client events.
|
|
InitializeClient(_client);
|
|
|
|
_netcom = new RaindropNetcom(this);
|
|
_state = new StateManager(this);
|
|
MediaManager = new MediaManager(this);
|
|
|
|
//commandsManager = new CommandsManager(this);
|
|
//ContextActionManager = new ContextActionsManager(this);
|
|
//RegisterContextActions();
|
|
_movement = new RaindropMovement(this);
|
|
|
|
|
|
//rlv = new RLVManager(this);
|
|
_gridManager = new GridManager(UserDir);
|
|
|
|
_names = new NameManager(this);
|
|
Cof = new CurrentOutfitFolder(this);
|
|
|
|
_agentsTracker = new AgentsTracker(this);
|
|
|
|
//ui_manager = new UIManager(this);
|
|
//mainCanvas.InitializeControls();
|
|
|
|
//mainCanvas.Load += new EventHandler(mainForm_Load);
|
|
//pluginManager = new PluginManager(this);
|
|
//pluginManager.ScanAndLoadPlugins();
|
|
|
|
// chatManger = new ChatManager(this);
|
|
}
|
|
|
|
private void InitializeClient(GridClient client)
|
|
{
|
|
string LightweightNetwork = "LightweightNetwork"; //i think this is like a only-retrieve simple data like chats mode.
|
|
bool isLightweightNetwork = false;
|
|
try
|
|
{
|
|
isLightweightNetwork = GlobalSettings[LightweightNetwork];
|
|
|
|
} catch (Exception ex)
|
|
{
|
|
Logger.Log("Failed loading Settings.LightweightNetwork: ", Helpers.LogLevel.Warning, client, ex);
|
|
GlobalSettings[LightweightNetwork] = isLightweightNetwork; //set some defaults so that next run may succeed.
|
|
}
|
|
|
|
string LightweightCPU = "LightweightCPU"; //i think this is like a no-render mode.
|
|
bool isLightweightCPU = false;
|
|
try
|
|
{
|
|
isLightweightCPU = GlobalSettings[LightweightCPU];
|
|
|
|
} catch (Exception ex)
|
|
{
|
|
Logger.Log("Failed loading Settings.LightweightCPU: ", Helpers.LogLevel.Warning, client, ex);
|
|
GlobalSettings[LightweightCPU] = isLightweightCPU; //set some defaults so that next run may succeed.
|
|
}
|
|
|
|
if (isLightweightNetwork)
|
|
{
|
|
client.Settings.ALWAYS_REQUEST_OBJECTS = false;
|
|
client.Settings.SEND_AGENT_UPDATES = false;
|
|
|
|
}
|
|
else
|
|
{
|
|
client.Settings.ALWAYS_REQUEST_OBJECTS = true;
|
|
client.Settings.SEND_AGENT_UPDATES = true;
|
|
|
|
}
|
|
|
|
if (isLightweightCPU)
|
|
{
|
|
client.Settings.STORE_LAND_PATCHES = false;
|
|
client.Settings.ALWAYS_DECODE_OBJECTS = false;
|
|
client.Settings.ENABLE_SIMSTATS = false;
|
|
|
|
}
|
|
else
|
|
{
|
|
client.Settings.STORE_LAND_PATCHES = true;
|
|
client.Settings.ALWAYS_DECODE_OBJECTS = true;
|
|
client.Settings.ENABLE_SIMSTATS = true;
|
|
|
|
}
|
|
|
|
client.Settings.MULTIPLE_SIMS = false;
|
|
|
|
client.Settings.USE_INTERPOLATION_TIMER = false;
|
|
client.Settings.OBJECT_TRACKING = true;
|
|
client.Settings.SEND_AGENT_THROTTLE = true;
|
|
|
|
client.Settings.USE_ASSET_CACHE = true;
|
|
//1. init res dir: internalStrgeRoot/openmetavese_data.
|
|
OpenMetaverse.Settings.RESOURCE_DIR = Path.Combine(UserDir, "openmetaverse_data");
|
|
Logger.Log("resource root: " + OpenMetaverse.Settings.RESOURCE_DIR, Helpers.LogLevel.Info);
|
|
//2. init asset cache dir: internalStrgeRoot/openmetavese_data/cache.
|
|
client.Settings.ASSET_CACHE_DIR = Path.Combine(OpenMetaverse.Settings.RESOURCE_DIR, "cache");
|
|
Logger.Log("Asset cache: " + client.Settings.ASSET_CACHE_DIR, Helpers.LogLevel.Info);
|
|
client.Assets.Cache.AutoPruneEnabled = false;
|
|
client.Assets.Cache.ComputeAssetCacheFilename = ComputeCacheName;
|
|
|
|
client.Throttle.Total = 5000000f; //0.625 megabytes.
|
|
client.Settings.THROTTLE_OUTGOING_PACKETS = true; //please throttle to be good boy.
|
|
client.Settings.LOGIN_TIMEOUT = 47 * 1000; //120
|
|
client.Settings.SIMULATOR_TIMEOUT = 180 * 1000; //180
|
|
client.Settings.MAX_CONCURRENT_TEXTURE_DOWNLOADS = 20;
|
|
|
|
client.Self.Movement.AutoResetControls = false;
|
|
client.Self.Movement.UpdateInterval = 2500; //2.5 seconds?
|
|
client.Settings.DISABLE_AGENT_UPDATE_DUPLICATE_CHECK = false; //lets be not-rude.
|
|
|
|
RegisterClientEvents(client);
|
|
}
|
|
|
|
public string ComputeCacheName(string cacheDir, UUID assetID)
|
|
{
|
|
string fileName = assetID.ToString();
|
|
string dir = cacheDir
|
|
+ Path.DirectorySeparatorChar + fileName.Substring(0, 1)
|
|
+ Path.DirectorySeparatorChar + fileName.Substring(1, 1);
|
|
try
|
|
{
|
|
if (!Directory.Exists(dir))
|
|
{
|
|
Directory.CreateDirectory(dir);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
return Path.Combine(cacheDir, fileName);
|
|
}
|
|
return Path.Combine(dir, fileName);
|
|
}
|
|
|
|
private void RegisterClientEvents(GridClient client)
|
|
{
|
|
//log
|
|
//OpenMetaverse.Logger.OnLogMessage += Logger_OnLogMessage;
|
|
|
|
client.Groups.CurrentGroups += new EventHandler<CurrentGroupsEventArgs>(Groups_CurrentGroups);
|
|
client.Groups.GroupLeaveReply += new EventHandler<GroupOperationEventArgs>(Groups_GroupsChanged);
|
|
client.Groups.GroupDropped += new EventHandler<GroupDroppedEventArgs>(Groups_GroupsChanged);
|
|
client.Groups.GroupJoinedReply += new EventHandler<GroupOperationEventArgs>(Groups_GroupsChanged);
|
|
if (_netcom != null)
|
|
_netcom.ClientConnected += new EventHandler<EventArgs>(netcom_ClientConnected);
|
|
client.Network.LoginProgress += new EventHandler<LoginProgressEventArgs>(Network_LoginProgress);
|
|
}
|
|
|
|
private void UnregisterClientEvents(GridClient client)
|
|
{
|
|
client.Groups.CurrentGroups -= new EventHandler<CurrentGroupsEventArgs>(Groups_CurrentGroups);
|
|
client.Groups.GroupLeaveReply -= new EventHandler<GroupOperationEventArgs>(Groups_GroupsChanged);
|
|
client.Groups.GroupDropped -= new EventHandler<GroupDroppedEventArgs>(Groups_GroupsChanged);
|
|
client.Groups.GroupJoinedReply -= new EventHandler<GroupOperationEventArgs>(Groups_GroupsChanged);
|
|
if (_netcom != null)
|
|
_netcom.ClientConnected -= new EventHandler<EventArgs>(netcom_ClientConnected);
|
|
client.Network.LoginProgress -= new EventHandler<LoginProgressEventArgs>(Network_LoginProgress);
|
|
}
|
|
|
|
private void GetWorldTimeZone()
|
|
{
|
|
try
|
|
{
|
|
foreach (TimeZoneInfo tz in TimeZoneInfo.GetSystemTimeZones())
|
|
{
|
|
if (tz.Id == "Pacific Standard Time" || tz.Id == "America/Los_Angeles")
|
|
{
|
|
WordTimeZone = tz;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
|
|
public DateTime GetWorldTime()
|
|
{
|
|
DateTime now;
|
|
|
|
try
|
|
{
|
|
if (WordTimeZone != null)
|
|
now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, WordTimeZone);
|
|
else
|
|
now = DateTime.UtcNow.AddHours(-7);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
now = DateTime.UtcNow.AddHours(-7);
|
|
}
|
|
|
|
return now;
|
|
}
|
|
|
|
|
|
public void Reconnect()
|
|
{
|
|
Notification.DisplayNotification("Attempting to reconnect...", ChatBufferTextStyle.StatusDarkBlue);
|
|
Logger.Log("Attempting to reconnect", Helpers.LogLevel.Info, _client);
|
|
GridClient oldClient = _client;
|
|
_client = new GridClient();
|
|
UnregisterClientEvents(oldClient);
|
|
InitializeClient(_client);
|
|
OnClientChanged(new ClientChangedEventArgs(oldClient, _client));
|
|
_netcom.Login();
|
|
}
|
|
|
|
// invoke dispose pattern on all my objects
|
|
public void CleanUp()
|
|
{
|
|
MarkEndExecution();
|
|
|
|
if (_agentsTracker != null)
|
|
{
|
|
_agentsTracker.Dispose();
|
|
_agentsTracker = null;
|
|
}
|
|
|
|
if (Cof != null)
|
|
{
|
|
Cof.Dispose();
|
|
Cof = null;
|
|
}
|
|
|
|
if (_names != null)
|
|
{
|
|
_names.Dispose();
|
|
_names = null;
|
|
}
|
|
|
|
if (_gridManager != null)
|
|
{
|
|
_gridManager.Dispose();
|
|
_gridManager = null;
|
|
}
|
|
|
|
//if (rlv != null)
|
|
//{
|
|
// rlv.Dispose();
|
|
// rlv = null;
|
|
//}
|
|
|
|
if (_client != null)
|
|
{
|
|
UnregisterClientEvents(_client);
|
|
}
|
|
|
|
//if (pluginManager != null)
|
|
//{
|
|
// pluginManager.Dispose();
|
|
// pluginManager = null;
|
|
//}
|
|
|
|
if (_movement != null)
|
|
{
|
|
_movement.Dispose();
|
|
_movement = null;
|
|
}
|
|
//if (commandsManager != null)
|
|
//{
|
|
// commandsManager.Dispose();
|
|
// commandsManager = null;
|
|
//}
|
|
//if (ContextActionManager != null)
|
|
//{
|
|
// ContextActionManager.Dispose();
|
|
// ContextActionManager = null;
|
|
//}
|
|
if (MediaManager != null)
|
|
{
|
|
MediaManager.Dispose();
|
|
MediaManager = null;
|
|
}
|
|
if (_state != null)
|
|
{
|
|
_state.Dispose();
|
|
_state = null;
|
|
}
|
|
if (_netcom != null)
|
|
{
|
|
_netcom.Dispose();
|
|
_netcom = null;
|
|
}
|
|
//if (mainCanvas != null)
|
|
//{
|
|
// mainCanvas.Load -= new EventHandler(mainForm_Load);
|
|
//}
|
|
Logger.Log("RaindropInstance finished cleaning up.", Helpers.LogLevel.Debug);
|
|
}
|
|
|
|
|
|
|
|
void netcom_ClientConnected(object sender, EventArgs e)
|
|
{
|
|
_client.Self.RequestMuteList();
|
|
}
|
|
|
|
void Network_LoginProgress(object sender, LoginProgressEventArgs e)
|
|
{
|
|
if (e.Status == LoginStatus.ConnectingToSim)
|
|
{
|
|
try
|
|
{
|
|
if (!Directory.Exists(ClientDir))
|
|
{
|
|
Directory.CreateDirectory(ClientDir);
|
|
}
|
|
ClientSettings = new Settings(Path.Combine(ClientDir, "client_settings.xml"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Log("Failed to create client directory", Helpers.LogLevel.Warning, ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Fetches avatar name
|
|
/// </summary>
|
|
/// <param name="key">Avatar UUID</param>
|
|
/// <param name="blocking">Should we wait until the name is retrieved</param>
|
|
/// <returns>Avatar name</returns>
|
|
[Obsolete("Use Instance.Names.Get() instead")]
|
|
public string GetAvatarName(UUID key, bool blocking)
|
|
{
|
|
return Names.Get(key, blocking);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches avatar name from cache, if not in cache will request name from the server
|
|
/// </summary>
|
|
/// <param name="key">Avatar UUID</param>
|
|
/// <returns>Avatar name</returns>
|
|
[Obsolete("Use Instance.Names.Get() instead")]
|
|
public string GetAvatarName(UUID key)
|
|
{
|
|
return Names.Get(key);
|
|
}
|
|
|
|
void Groups_GroupsChanged(object sender, EventArgs e)
|
|
{
|
|
_client.Groups.RequestCurrentGroups();
|
|
}
|
|
|
|
public static string SafeFileName(string fileName)
|
|
{
|
|
foreach (char lDisallowed in Path.GetInvalidFileNameChars())
|
|
{
|
|
fileName = fileName.Replace(lDisallowed.ToString(), "_");
|
|
}
|
|
|
|
return fileName;
|
|
}
|
|
|
|
//obtains the relevant filepath/name.
|
|
public string ChatFileName(string session)
|
|
{
|
|
string fileName = session;
|
|
|
|
foreach (char lDisallowed in System.IO.Path.GetInvalidFileNameChars())
|
|
{
|
|
fileName = fileName.Replace(lDisallowed.ToString(), "_");
|
|
}
|
|
|
|
return Path.Combine(ClientDir, fileName);
|
|
}
|
|
|
|
//this method will log all messages to the relevant file.
|
|
public void LogClientMessage(string sessionName, string message)
|
|
{
|
|
if (_globalSettings["disable_chat_im_log"]) return;
|
|
|
|
lock (this)
|
|
{
|
|
try
|
|
{
|
|
File.AppendAllText(ChatFileName(sessionName),
|
|
DateTime.Now.ToString("yyyy-MM-dd [HH:mm:ss] ") + message + Environment.NewLine);
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
|
|
void Groups_CurrentGroups(object sender, CurrentGroupsEventArgs e)
|
|
{
|
|
this.Groups = e.Groups;
|
|
}
|
|
|
|
// for simplicity, we will always use internal dir for settings.
|
|
private void InitializeLoggingAndConfigAndUserDirectory()
|
|
{
|
|
try
|
|
{
|
|
var internalDir = DirectoryHelpers.GetInternalStorageDir();
|
|
UserDir = internalDir;
|
|
if (!Directory.Exists(UserDir))
|
|
{
|
|
Directory.CreateDirectory(UserDir);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
Logger.Log("App termination due to: unable to create UserDir: " + UserDir, Helpers.LogLevel.Error);
|
|
#if !UNITY_EDITOR
|
|
Application.Quit();
|
|
#endif
|
|
|
|
#if UNITY_EDITOR
|
|
EditorApplication.isPlaying = false;
|
|
#endif
|
|
};
|
|
|
|
_globalLogFile = Path.Combine(UserDir, _programname + ".log");
|
|
_globalSettings = new Settings(Path.Combine(UserDir, "settings.xml"));
|
|
//frmSettings.InitSettigs(globalSettings, monoRuntime);
|
|
}
|
|
|
|
public GridClient Client
|
|
{
|
|
get { return _client; }
|
|
}
|
|
|
|
public RaindropNetcom Netcom
|
|
{
|
|
get { return _netcom; }
|
|
}
|
|
|
|
public StateManager State
|
|
{
|
|
get { return _state; }
|
|
}
|
|
|
|
public AgentsTracker AgentsTracker {
|
|
get { return _agentsTracker; }
|
|
}
|
|
private AgentsTracker _agentsTracker;
|
|
|
|
//public TabsConsole TabConsole
|
|
//{
|
|
// get { return mainForm.TabConsole; }
|
|
//}
|
|
|
|
public void HandleThreadException(object sender, ThreadExceptionEventArgs e)
|
|
{
|
|
Logger.Log("Unhandled thread exception: "
|
|
+ e.Exception.Message + Environment.NewLine
|
|
+ e.Exception.StackTrace + Environment.NewLine,
|
|
Helpers.LogLevel.Error,
|
|
_client);
|
|
}
|
|
|
|
#region Crash reporting
|
|
FileStream _markerLock = null;
|
|
private string _programname = "RaindropViewer";
|
|
private readonly string _extAppDataDir;
|
|
|
|
public bool AnotherInstanceRunning()
|
|
{
|
|
// We have successfuly obtained lock
|
|
if (_markerLock != null && _markerLock.CanWrite)
|
|
{
|
|
Logger.Log("No other instances detected, marker file already locked", Helpers.LogLevel.Debug);
|
|
return false || MonoRuntime;
|
|
}
|
|
|
|
try
|
|
{
|
|
_markerLock = new FileStream(CrashMarkerFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
|
|
Logger.Log(string.Format("Successfully created and locked marker file {0}", CrashMarkerFileName), Helpers.LogLevel.Debug);
|
|
return false || MonoRuntime;
|
|
}
|
|
catch
|
|
{
|
|
_markerLock = null;
|
|
Logger.Log(string.Format("Another instance detected, marker fils {0} locked", CrashMarkerFileName), Helpers.LogLevel.Debug);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public LastExecStatus GetLastExecStatus()
|
|
{
|
|
// Crash marker file found and is not locked by us
|
|
if (File.Exists(CrashMarkerFileName) && _markerLock == null)
|
|
{
|
|
Logger.Log(string.Format("Found crash marker file {0}", CrashMarkerFileName), Helpers.LogLevel.Debug);
|
|
return LastExecStatus.OtherCrash;
|
|
}
|
|
else
|
|
{
|
|
Logger.Log(string.Format("No crash marker file {0} found", CrashMarkerFileName), Helpers.LogLevel.Debug);
|
|
return LastExecStatus.Normal;
|
|
}
|
|
}
|
|
|
|
public void MarkStartExecution()
|
|
{
|
|
Logger.Log(string.Format("Marking start of execution run, creating file: {0}", CrashMarkerFileName), Helpers.LogLevel.Debug);
|
|
try
|
|
{
|
|
File.Create(CrashMarkerFileName).Dispose();
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
public void MarkEndExecution()
|
|
{
|
|
Logger.Log(string.Format("Marking end of execution run, deleting file: {0}", CrashMarkerFileName), Helpers.LogLevel.Debug);
|
|
try
|
|
{
|
|
if (_markerLock != null)
|
|
{
|
|
_markerLock.Close();
|
|
_markerLock.Dispose();
|
|
_markerLock = null;
|
|
}
|
|
|
|
File.Delete(CrashMarkerFileName);
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
internal void SetAppDataDir(string appDataPath)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
#endregion Crash reporting
|
|
|
|
#region Context Actions
|
|
//void RegisterContextActions()
|
|
//{
|
|
// ContextActionManager.RegisterContextAction(typeof(Primitive), "Save as DAE...", ExportDAEHander);
|
|
// ContextActionManager.RegisterContextAction(typeof(Primitive), "Copy UUID to clipboard", CopyObjectUUIDHandler);
|
|
//}
|
|
|
|
//void DeregisterContextActions()
|
|
//{
|
|
// ContextActionManager.DeregisterContextAction(typeof(Primitive), "Save as DAE...");
|
|
// ContextActionManager.DeregisterContextAction(typeof(Primitive), "Copy UUID to clipboard");
|
|
//}
|
|
|
|
//void ExportDAEHander(object sender, EventArgs e)
|
|
//{
|
|
// MainForm.DisplayColladaConsole((Primitive)sender);
|
|
//}
|
|
|
|
//void CopyObjectUUIDHandler(object sender, EventArgs e)
|
|
//{
|
|
// if (mainForm.InvokeRequired)
|
|
// {
|
|
// if (mainForm.IsHandleCreated || !MonoRuntime)
|
|
// {
|
|
// mainForm.Invoke(new MethodInvoker(() => CopyObjectUUIDHandler(sender, e)));
|
|
// }
|
|
// return;
|
|
// }
|
|
|
|
// Clipboard.SetText(((Primitive)sender).ID.ToString());
|
|
//}
|
|
|
|
#endregion Context Actions
|
|
|
|
|
|
//no longer using this as we have configured log4net :)
|
|
private void Logger_OnLogMessage(object message, Helpers.LogLevel level)
|
|
{
|
|
if (level == Helpers.LogLevel.Debug)
|
|
{
|
|
Debug.Log(message);
|
|
}
|
|
else if (level == Helpers.LogLevel.Error)
|
|
{
|
|
Debug.LogError(message);
|
|
}
|
|
else if (level == Helpers.LogLevel.Info)
|
|
{
|
|
Debug.Log(message);
|
|
}
|
|
else if (level == Helpers.LogLevel.Warning)
|
|
{
|
|
Debug.LogWarning(message);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError(message);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
#region Event classes
|
|
public class ClientChangedEventArgs : EventArgs
|
|
{
|
|
private GridClient m_OldClient;
|
|
private GridClient m_Client;
|
|
|
|
public GridClient OldClient { get { return m_OldClient; } }
|
|
public GridClient Client { get { return m_Client; } }
|
|
|
|
public ClientChangedEventArgs(GridClient OldClient, GridClient Client)
|
|
{
|
|
m_OldClient = OldClient;
|
|
m_Client = Client;
|
|
}
|
|
}
|
|
|
|
#endregion Event classes
|
|
}
|