WIP of porting radegast viewer source code

This commit is contained in:
alexiscatnip
2021-05-10 02:17:18 +08:00
parent 4bf87102f2
commit 282fb334ca
69 changed files with 13121 additions and 302 deletions
+10
View File
@@ -0,0 +1,10 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DebugTextVM : MonoBehaviour
{
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f003e7629ecbbdb4c9867c281c3c59c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+59
View File
@@ -0,0 +1,59 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//attached to panel UI. simply toggles UI panels.
public class DebugToggleManager : MonoBehaviour
{
public Stack<GameObject> panelStack;
public GameObject loginPanel;
public GameObject gamePanel;
public GameObject defaultOnPanel;
private void Awake()
{
panelStack = new Stack<GameObject>();
defaultOnPanel = loginPanel;
addPaneltoView(defaultOnPanel);
removeTopPanelFromView();
gamePanel.SetActive(false);
}
public void togglePanel(GameObject panel)
{
if (panel.activeInHierarchy == false)
{
addPaneltoView(panel);
} else
{
removeTopPanelFromView();
}
}
public void removeTopPanelFromView()
{
GameObject toppanel;
if (panelStack.Count != 0)
{
toppanel = panelStack.Peek();
panelStack.Pop();
toppanel.SetActive(false);
}
}
public void addPaneltoView(GameObject defaultOnPanel)
{
panelStack.Push(defaultOnPanel);
defaultOnPanel.SetActive(true);
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9047a9f086d8beb429cb9bad0fe6fbd7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 5517ceddb63c378498db7ef3905c90f3
guid: 538b2f91dbf71f54eb8346fd20194b00
folderAsset: yes
DefaultImporter:
externalObjects: {}
+242
View File
@@ -0,0 +1,242 @@
// ConcurrentQueue.cs
//
// Copyright (c) 2008 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
// Note this is slightly modified from the original from Mono for compatibility with .Net 3.5
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace System.Threading.Collections
{
public class ConcurrentQueue<T> : IEnumerable<T>, ICollection, ISerializable, IDeserializationCallback
{
class Node
{
public T Value;
public Node Next;
}
Node _head = new Node();
Node _tail;
int _count;
/// <summary>
/// </summary>
public ConcurrentQueue()
{
_tail = _head;
}
public ConcurrentQueue(IEnumerable<T> enumerable)
: this()
{
foreach (T item in enumerable)
Enqueue(item);
}
public void Enqueue(T item)
{
var node = new Node { Value = item };
Node oldTail = null;
bool update = false;
while (!update)
{
oldTail = _tail;
var oldNext = oldTail.Next;
// Did tail was already updated ?
if (_tail == oldTail)
{
if (oldNext == null)
{
// The place is for us
update = Interlocked.CompareExchange(ref _tail.Next, node, null) == null;
}
else
{
// another Thread already used the place so give him a hand by putting tail where it should be
Interlocked.CompareExchange(ref _tail, oldNext, oldTail);
}
}
}
// At this point we added correctly our node, now we have to update tail. If it fails then it will be done by another thread
Interlocked.CompareExchange(ref _tail, node, oldTail);
Interlocked.Increment(ref _count);
}
/// <summary>
/// </summary>
/// <returns></returns>
public bool TryDequeue(out T value)
{
value = default(T);
bool advanced = false;
while (!advanced)
{
Node oldHead = _head;
Node oldTail = _tail;
Node oldNext = oldHead.Next;
if (oldHead == _head)
{
// Empty case ?
if (oldHead == oldTail)
{
// This should be false then
if (oldNext != null)
{
// If not then the linked list is mal formed, update tail
Interlocked.CompareExchange(ref _tail, oldNext, oldTail);
}
value = default(T);
return false;
}
else
{
value = oldNext.Value;
advanced = Interlocked.CompareExchange(ref _head, oldNext, oldHead) == oldHead;
}
}
}
Interlocked.Decrement(ref _count);
return true;
}
/// <summary>
/// </summary>
/// <returns></returns>
public bool TryPeek(out T value)
{
if (IsEmpty)
{
value = default(T);
return false;
}
Node first = _head.Next;
value = first.Value;
return true;
}
public void Clear()
{
_count = 0;
_tail = _head = new Node();
}
IEnumerator IEnumerable.GetEnumerator()
{
return InternalGetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return InternalGetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return InternalGetEnumerator();
}
IEnumerator<T> InternalGetEnumerator()
{
Node myHead = _head;
while ((myHead = myHead.Next) != null)
{
yield return myHead.Value;
}
}
void ICollection.CopyTo(Array array, int index)
{
T[] dest = array as T[];
if (dest == null)
return;
CopyTo(dest, index);
}
public void CopyTo(T[] dest, int index)
{
IEnumerator<T> e = InternalGetEnumerator();
int i = index;
while (e.MoveNext())
{
dest[i++] = e.Current;
}
}
public T[] ToArray()
{
T[] dest = new T[_count];
CopyTo(dest, 0);
return dest;
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotImplementedException();
}
bool ICollection.IsSynchronized
{
get { return true; }
}
public void OnDeserialization(object sender)
{
throw new NotImplementedException();
}
readonly object _syncRoot = new object();
object ICollection.SyncRoot
{
get { return _syncRoot; }
}
public int Count
{
get
{
return _count;
}
}
public bool IsEmpty
{
get
{
return _count == 0;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18a25d882e7671d47becffdc6de1f734
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
{
"name": "DisruptorASMDEF",
"rootNamespace": "",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1364d97af688c264f94c622d729b2059
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+275
View File
@@ -0,0 +1,275 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace DisruptorUnity3d
{
/// <summary>
/// Implementation of the Disruptor pattern
/// </summary>
/// <typeparam name="T">the type of item to be stored</typeparam>
public class RingBuffer<T>
{
private readonly T[] _entries;
private readonly int _modMask;
private Volatile.PaddedLong _consumerCursor = new Volatile.PaddedLong();
private Volatile.PaddedLong _producerCursor = new Volatile.PaddedLong();
/// <summary>
/// Creates a new RingBuffer with the given capacity
/// </summary>
/// <param name="capacity">The capacity of the buffer</param>
/// <remarks>Only a single thread may attempt to consume at any one time</remarks>
public RingBuffer(int capacity)
{
capacity = NextPowerOfTwo(capacity);
_modMask = capacity - 1;
_entries = new T[capacity];
}
/// <summary>
/// The maximum number of items that can be stored
/// </summary>
public int Capacity
{
get { return _entries.Length; }
}
public T this[long index]
{
get { unchecked { return _entries[index & _modMask]; } }
set { unchecked { _entries[index & _modMask] = value; } }
}
/// <summary>
/// Removes an item from the buffer.
/// </summary>
/// <returns>The next available item</returns>
public T Dequeue()
{
var next = _consumerCursor.ReadAcquireFence() + 1;
while (_producerCursor.ReadAcquireFence() < next) // makes sure we read the data from _entries after we have read the producer cursor
{
Thread.SpinWait(1);
}
var result = this[next];
_consumerCursor.WriteReleaseFence(next); // makes sure we read the data from _entries before we update the consumer cursor
return result;
}
/// <summary>
/// Attempts to remove an items from the queue
/// </summary>
/// <param name="obj">the items</param>
/// <returns>True if successful</returns>
public bool TryDequeue(out T obj)
{
var next = _consumerCursor.ReadAcquireFence() + 1;
if (_producerCursor.ReadAcquireFence() < next)
{
obj = default(T);
return false;
}
obj = Dequeue();
return true;
}
/// <summary>
/// Add an item to the buffer
/// </summary>
/// <param name="item"></param>
public void Enqueue(T item)
{
var next = _producerCursor.ReadAcquireFence() + 1;
long wrapPoint = next - _entries.Length;
long min = _consumerCursor.ReadAcquireFence();
while (wrapPoint > min)
{
min = _consumerCursor.ReadAcquireFence();
Thread.SpinWait(1);
}
this[next] = item;
_producerCursor.WriteReleaseFence(next); // makes sure we write the data in _entries before we update the producer cursor
}
/// <summary>
/// The number of items in the buffer
/// </summary>
/// <remarks>for indicative purposes only, may contain stale data</remarks>
public int Count { get { return (int)(_producerCursor.ReadFullFence() - _consumerCursor.ReadFullFence()); } }
private static int NextPowerOfTwo(int x)
{
var result = 2;
while (result < x)
{
result <<= 1;
}
return result;
}
}
public static class Volatile
{
private const int CacheLineSize = 64;
[StructLayout(LayoutKind.Explicit, Size = CacheLineSize * 2)]
public struct PaddedLong
{
[FieldOffset(CacheLineSize)]
private long _value;
/// <summary>
/// Create a new <see cref="PaddedLong"/> with the given initial value.
/// </summary>
/// <param name="value">Initial value</param>
public PaddedLong(long value)
{
_value = value;
}
/// <summary>
/// Read the value without applying any fence
/// </summary>
/// <returns>The current value</returns>
public long ReadUnfenced()
{
return _value;
}
/// <summary>
/// Read the value applying acquire fence semantic
/// </summary>
/// <returns>The current value</returns>
public long ReadAcquireFence()
{
var value = _value;
Thread.MemoryBarrier();
return value;
}
/// <summary>
/// Read the value applying full fence semantic
/// </summary>
/// <returns>The current value</returns>
public long ReadFullFence()
{
Thread.MemoryBarrier();
return _value;
}
/// <summary>
/// Read the value applying a compiler only fence, no CPU fence is applied
/// </summary>
/// <returns>The current value</returns>
[MethodImpl(MethodImplOptions.NoOptimization)]
public long ReadCompilerOnlyFence()
{
return _value;
}
/// <summary>
/// Write the value applying release fence semantic
/// </summary>
/// <param name="newValue">The new value</param>
public void WriteReleaseFence(long newValue)
{
Thread.MemoryBarrier();
_value = newValue;
}
/// <summary>
/// Write the value applying full fence semantic
/// </summary>
/// <param name="newValue">The new value</param>
public void WriteFullFence(long newValue)
{
Thread.MemoryBarrier();
_value = newValue;
}
/// <summary>
/// Write the value applying a compiler fence only, no CPU fence is applied
/// </summary>
/// <param name="newValue">The new value</param>
[MethodImpl(MethodImplOptions.NoOptimization)]
public void WriteCompilerOnlyFence(long newValue)
{
_value = newValue;
}
/// <summary>
/// Write without applying any fence
/// </summary>
/// <param name="newValue">The new value</param>
public void WriteUnfenced(long newValue)
{
_value = newValue;
}
/// <summary>
/// Atomically set the value to the given updated value if the current value equals the comparand
/// </summary>
/// <param name="newValue">The new value</param>
/// <param name="comparand">The comparand (expected value)</param>
/// <returns></returns>
public bool AtomicCompareExchange(long newValue, long comparand)
{
return Interlocked.CompareExchange(ref _value, newValue, comparand) == comparand;
}
/// <summary>
/// Atomically set the value to the given updated value
/// </summary>
/// <param name="newValue">The new value</param>
/// <returns>The original value</returns>
public long AtomicExchange(long newValue)
{
return Interlocked.Exchange(ref _value, newValue);
}
/// <summary>
/// Atomically add the given value to the current value and return the sum
/// </summary>
/// <param name="delta">The value to be added</param>
/// <returns>The sum of the current value and the given value</returns>
public long AtomicAddAndGet(long delta)
{
return Interlocked.Add(ref _value, delta);
}
/// <summary>
/// Atomically increment the current value and return the new value
/// </summary>
/// <returns>The incremented value.</returns>
public long AtomicIncrementAndGet()
{
return Interlocked.Increment(ref _value);
}
/// <summary>
/// Atomically increment the current value and return the new value
/// </summary>
/// <returns>The decremented value.</returns>
public long AtomicDecrementAndGet()
{
return Interlocked.Decrement(ref _value);
}
/// <summary>
/// Returns the string representation of the current value.
/// </summary>
/// <returns>the string representation of the current value.</returns>
public override string ToString()
{
var value = ReadFullFence();
return value.ToString();
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0ed5999a9ac5a0244b4e15b4e2a5c7ee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+74
View File
@@ -0,0 +1,74 @@
using System.Diagnostics;
using System.Threading;
using UnityEngine;
using Debug = UnityEngine.Debug;
using Random = System.Random;
namespace DisruptorUnity3d
{
public class Test : MonoBehaviour
{
static readonly Random Rng = new Random();
static readonly RingBuffer<int> Queue = new RingBuffer<int>(1000);
//static readonly ConcurrentQueue<int> Queue = new ConcurrentQueue<int>();
static readonly Stopwatch sw = new Stopwatch();
private const long Count = 5000000;//100000000;
private long _queued = 0;
private const long BatchSize = 20000;
private Thread _consumerThread;
private bool _printed = false;
private int numberToEnqueue;
public void Start()
{
Debug.Log("Started Test");
_consumerThread = new Thread(() =>
{
Debug.Log("Started consumer");
int expectedNumber = 0;
int previousNumber = 0;
for (long i = 0; i < Count; )
{
int val;
var dequeued = Queue.TryDequeue(out val);
if (dequeued)
{
if (expectedNumber != val)
Debug.Log("wrong value " + val + " ,correct: " + i + " ,previous: " + previousNumber);
previousNumber = val;
expectedNumber++;
++i;
}
}
Debug.Log(string.Format("Consumer done {0}", sw.Elapsed));
});
_consumerThread.Start();
sw.Start();
}
// Update is called once per frame
public void Update()
{
if (_queued >= Count && !_printed)
{
sw.Stop();
Debug.Log(string.Format("Producer done {0} {1}", sw.Elapsed, _queued));
_printed = true;
}
else
{
for (long i = 0; i < BatchSize && _queued < Count; ++i)
{
Queue.Enqueue(numberToEnqueue++);
++_queued;
}
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 35efa1e25d8cb8243afec9feafa02080
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -113,14 +113,14 @@ namespace OpenMetaverse.Http
if (postData == null)
{
// GET
//Logger.Log.Debug("[CapsClient] GET " + _Address);
Logger.DebugLog("[CapsClient] GET " + _Address);
_Request = CapsBase.DownloadStringAsync(_Address, _ClientCert, millisecondsTimeout, DownloadProgressHandler,
RequestCompletedHandler);
}
else
{
// POST
//Logger.Log.Debug("[CapsClient] POST (" + postData.Length + " bytes) " + _Address);
Logger.DebugLog("[CapsClient] POST (" + postData.Length + " bytes) " + _Address);
_Request = CapsBase.UploadDataAsync(_Address, _ClientCert, contentType, postData, millisecondsTimeout, null,
DownloadProgressHandler, RequestCompletedHandler);
}
@@ -171,8 +171,11 @@ namespace OpenMetaverse.Http
if (responseData != null)
{
Logger.DebugLog("RequestCompletedHandler" + ":" +" responseData is not null.");
try { result = OSDParser.Deserialize(responseData); }
catch (Exception ex) { error = ex; }
catch (Exception ex) {
Logger.Log("RequestCompletedHandler" + ":" + " responseData is not null but ran an exception!.",Helpers.LogLevel.Error);
error = ex; }
}
FireCompleteCallback(result, error);
@@ -185,11 +188,11 @@ namespace OpenMetaverse.Http
{
try
{
callback(this, result, error);
callback(this, result, error); //exception is "notimplementedexception"
}
catch (Exception ex)
{
Logger.DebugLog($"CapsBase.GetResponse() {_CapName} : {ex.Message}");
Logger.DebugLog($"CapsBase.GetResponse() {_CapName} : {ex.Message} : {ex.ToString()}"); //here the log is coming from!
Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
}
}
+1 -1
View File
@@ -330,7 +330,7 @@ namespace OpenMetaverse
{
Logger.Log("No Message handler exists for event " + eventName + ". Unable to decode. Will try Generic Handler next",
Helpers.LogLevel.Warning);
Logger.Log("Please report this information at https://radegast.life/bugs/issue-entry/: \n" + body,
Logger.Log("Please report this information at https://eerbsitehere.com: \n" + body,
Helpers.LogLevel.Debug);
// try generic decoder next which takes a caps event and tries to match it to an existing packet
@@ -1,9 +1,7 @@
{
"name": "LibreMetaverseAssembly",
"rootNamespace": "",
"references": [
""
],
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
+2
View File
@@ -1619,6 +1619,8 @@ namespace OpenMetaverse
LoginErrorKey = "no connection";
UpdateLoginStatus(LoginStatus.Failed, error.Message);
}
}
/// <summary>
+688
View File
@@ -0,0 +1,688 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace Raindrop
{
public class CurrentOutfitFolder : IDisposable
{
#region Fields
GridClient Client;
RaindropInstance Instance;
bool InitiCOF = false;
bool AppearanceSent = false;
bool COFReady = false;
bool InitialUpdateDone = false;
public Dictionary<UUID, InventoryItem> Content = new Dictionary<UUID, InventoryItem>();
public InventoryFolder COF;
#endregion Fields
#region Construction and disposal
public CurrentOutfitFolder(RaindropInstance instance)
{
this.Instance = instance;
this.Client = instance.Client;
Instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
RegisterClientEvents(Client);
}
public void Dispose()
{
UnregisterClientEvents(Client);
Instance.ClientChanged -= new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
}
#endregion Construction and disposal
#region Event handling
void instance_ClientChanged(object sender, ClientChangedEventArgs e)
{
UnregisterClientEvents(Client);
Client = e.Client;
RegisterClientEvents(Client);
}
void RegisterClientEvents(GridClient client)
{
client.Network.EventQueueRunning += new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
client.Inventory.FolderUpdated += new EventHandler<FolderUpdatedEventArgs>(Inventory_FolderUpdated);
client.Inventory.ItemReceived += new EventHandler<ItemReceivedEventArgs>(Inventory_ItemReceived);
client.Appearance.AppearanceSet += new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
client.Objects.KillObject += new EventHandler<KillObjectEventArgs>(Objects_KillObject);
}
void UnregisterClientEvents(GridClient client)
{
client.Network.EventQueueRunning -= new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
client.Inventory.FolderUpdated -= new EventHandler<FolderUpdatedEventArgs>(Inventory_FolderUpdated);
client.Inventory.ItemReceived -= new EventHandler<ItemReceivedEventArgs>(Inventory_ItemReceived);
client.Appearance.AppearanceSet -= new EventHandler<AppearanceSetEventArgs>(Appearance_AppearanceSet);
client.Objects.KillObject -= new EventHandler<KillObjectEventArgs>(Objects_KillObject);
lock (Content) Content.Clear();
InitiCOF = false;
AppearanceSent = false;
COFReady = false;
InitialUpdateDone = false;
}
void Appearance_AppearanceSet(object sender, AppearanceSetEventArgs e)
{
AppearanceSent = true;
if (COFReady)
{
InitialUpdate();
}
}
void Inventory_ItemReceived(object sender, ItemReceivedEventArgs e)
{
bool partOfCOF = false;
var links = ContentLinks();
foreach (var cofItem in links)
{
if (cofItem.AssetUUID == e.Item.UUID)
{
partOfCOF = true;
break;
}
}
if (partOfCOF)
{
lock (Content)
{
Content[e.Item.UUID] = e.Item;
}
}
if (Content.Count == links.Count)
{
COFReady = true;
if (AppearanceSent)
{
InitialUpdate();
}
lock (Content)
{
foreach (InventoryItem link in Content.Values)
{
if (link.InventoryType == InventoryType.Wearable)
{
InventoryWearable w = (InventoryWearable)link;
InventoryItem lk = links.Find(l => l.AssetUUID == w.UUID);
// Logger.DebugLog(string.Format("\nName: {0}\nDescription: {1}\nType: {2} - {3}", w.Name, lk == null ? "" : lk.Description, w.Flags.ToString(), w.WearableType.ToString())); ;
}
}
}
}
}
object FolderSync = new object();
void Inventory_FolderUpdated(object sender, FolderUpdatedEventArgs e)
{
if (COF == null) return;
if (e.FolderID == COF.UUID && e.Success)
{
COF = (InventoryFolder)Client.Inventory.Store[COF.UUID];
lock (FolderSync)
{
lock (Content) Content.Clear();
List<UUID> items = new List<UUID>();
List<UUID> owners = new List<UUID>();
foreach (var link in ContentLinks())
{
//if (Client.Inventory.Store.Contains(link.AssetUUID))
//{
// continue;
//}
items.Add(link.AssetUUID);
owners.Add(Client.Self.AgentID);
}
if (items.Count > 0)
{
Client.Inventory.RequestFetchInventory(items, owners);
}
}
}
}
void Objects_KillObject(object sender, KillObjectEventArgs e)
{
if (Client.Network.CurrentSim != e.Simulator) return;
Primitive prim = null;
if (Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(e.ObjectLocalID, out prim))
{
UUID invItem = GetAttachmentItem(prim);
if (invItem != UUID.Zero)
{
RemoveLink(invItem);
}
}
}
void Network_EventQueueRunning(object sender, EventQueueRunningEventArgs e)
{
if (e.Simulator == Client.Network.CurrentSim && !InitiCOF)
{
InitiCOF = true;
InitCOF();
}
}
#endregion Event handling
#region Private methods
void RequestDescendants(UUID folderID)
{
Client.Inventory.RequestFolderContents(folderID, Client.Self.AgentID, true, true, InventorySortOrder.ByDate);
}
void InitCOF()
{
List<InventoryBase> rootContent = Client.Inventory.Store.GetContents(Client.Inventory.Store.RootFolder.UUID);
foreach (InventoryBase baseItem in rootContent)
{
if (baseItem is InventoryFolder && ((InventoryFolder)baseItem).PreferredType == FolderType.CurrentOutfit)
{
COF = (InventoryFolder)baseItem;
break;
}
}
if (COF == null)
{
CreateCOF();
}
else
{
RequestDescendants(COF.UUID);
}
}
void CreateCOF()
{
UUID cofID = Client.Inventory.CreateFolder(Client.Inventory.Store.RootFolder.UUID, "Current Outfit", FolderType.CurrentOutfit);
if (Client.Inventory.Store.Items.ContainsKey(cofID) && Client.Inventory.Store.Items[cofID].Data is InventoryFolder)
{
COF = (InventoryFolder)Client.Inventory.Store.Items[cofID].Data;
COFReady = true;
if (AppearanceSent)
{
InitialUpdate();
}
}
}
void InitialUpdate()
{
if (InitialUpdateDone) return;
InitialUpdateDone = true;
lock (Content)
{
List<Primitive> myAtt = Client.Network.CurrentSim.ObjectsPrimitives.FindAll((Primitive p) => p.ParentID == Client.Self.LocalID);
foreach (InventoryItem item in Content.Values)
{
if (item is InventoryObject || item is InventoryAttachment)
{
if (!IsAttached(myAtt, item))
{
Client.Appearance.Attach(item, AttachmentPoint.Default, false);
}
}
}
}
}
#endregion Private methods
#region Public methods
/// <summary>
/// Get COF contents
/// </summary>
/// <returns>List if InventoryItems that can be part of appearance (attachments, wearables)</returns>
public List<InventoryItem> ContentLinks()
{
List<InventoryItem> ret = new List<InventoryItem>();
if (COF == null) return ret;
Client.Inventory.Store.GetContents(COF)
.FindAll(b => CanBeWorn(b) && ((InventoryItem)b).AssetType == AssetType.Link)
.ForEach(item => ret.Add((InventoryItem)item));
return ret;
}
/// <summary>
/// Get inventory ID of a prim
/// </summary>
/// <param name="prim">Prim to check</param>
/// <returns>Inventory ID of the object. UUID.Zero if not found</returns>
public static UUID GetAttachmentItem(Primitive prim)
{
if (prim.NameValues == null) return UUID.Zero;
for (int i = 0; i < prim.NameValues.Length; i++)
{
if (prim.NameValues[i].Name == "AttachItemID")
{
return (UUID)prim.NameValues[i].Value.ToString();
}
}
return UUID.Zero;
}
/// <summary>
/// Is an inventory item currently attached
/// </summary>
/// <param name="attachments">List of root prims that are attached to our avatar</param>
/// <param name="item">Inventory item to check</param>
/// <returns>True if the inventory item is attached to avatar</returns>
public static bool IsAttached(List<Primitive> attachments, InventoryItem item)
{
foreach (Primitive prim in attachments)
{
if (GetAttachmentItem(prim) == item.UUID)
{
return true;
}
}
return false;
}
/// <summary>
/// Checks if inventory item of Wearable type is worn
/// </summary>
/// <param name="currentlyWorn">Current outfit</param>
/// <param name="item">Item to check</param>
/// <returns>True if the item is worn</returns>
public static bool IsWorn(Dictionary<WearableType, AppearanceManager.WearableData> currentlyWorn, InventoryItem item)
{
foreach (var n in currentlyWorn.Values)
{
if (n.ItemID == item.UUID)
{
return true;
}
}
return false;
}
/// <summary>
/// Can this inventory type be worn
/// </summary>
/// <param name="item">Item to check</param>
/// <returns>True if the inventory item can be worn</returns>
public static bool CanBeWorn(InventoryBase item)
{
return item is InventoryWearable || item is InventoryAttachment || item is InventoryObject;
}
/// <summary>
/// Attach an inventory item
/// </summary>
/// <param name="item">Item to be attached</param>
/// <param name="point">Attachment point</param>
/// <param name="replace">Replace existing attachment at that point first?</param>
public void Attach(InventoryItem item, AttachmentPoint point, bool replace)
{
Client.Appearance.Attach(item, point, replace);
AddLink(item);
}
/// <summary>
/// Creates a new COF link
/// </summary>
/// <param name="item">Original item to be linked from COF</param>
public void AddLink(InventoryItem item)
{
if (item.InventoryType == InventoryType.Wearable && !IsBodyPart(item))
{
InventoryWearable w = (InventoryWearable)item;
int layer = 0;
string desc = string.Format("@{0}{1:00}", (int)w.WearableType, layer);
AddLink(item, desc);
}
else
{
AddLink(item, string.Empty);
}
}
/// <summary>
/// Creates a new COF link
/// </summary>
/// <param name="item">Original item to be linked from COF</param>
/// <param name="newDescription">Description for the link</param>
public void AddLink(InventoryItem item, string newDescription)
{
if (COF == null) return;
bool linkExists = false;
linkExists = null != ContentLinks().Find(itemLink => itemLink.AssetUUID == item.UUID);
if (!linkExists)
{
Client.Inventory.CreateLink(COF.UUID, item.UUID, item.Name, newDescription, AssetType.Link, item.InventoryType, UUID.Random(), (success, newItem) =>
{
if (success)
{
Client.Inventory.RequestFetchInventory(newItem.UUID, newItem.OwnerID);
}
});
}
}
/// <summary>
/// Remove a link to specified inventory item
/// </summary>
/// <param name="itemID">ID of the target inventory item for which we want link to be removed</param>
public void RemoveLink(UUID itemID)
{
RemoveLink(new List<UUID>(1) { itemID });
}
/// <summary>
/// Remove a link to specified inventory item
/// </summary>
/// <param name="itemIDs">List of IDs of the target inventory item for which we want link to be removed</param>
public void RemoveLink(List<UUID> itemIDs)
{
if (COF == null) return;
List<UUID> toRemove = new List<UUID>();
foreach (UUID itemID in itemIDs)
{
var links = ContentLinks().FindAll(itemLink => itemLink.AssetUUID == itemID);
links.ForEach(item => toRemove.Add(item.UUID));
}
Client.Inventory.Remove(toRemove, null);
}
/// <summary>
/// Remove attachment
/// </summary>
/// <param name="item">>Inventory item to be detached</param>
public void Detach(InventoryItem item)
{
var realItem = RealInventoryItem(item);
//if (Instance.RLV.AllowDetach(realItem))
//{
Client.Appearance.Detach(item);
RemoveLink(item.UUID);
//}
}
public List<InventoryItem> GetWornAt(WearableType type)
{
var ret = new List<InventoryItem>();
ContentLinks().ForEach(link =>
{
var item = RealInventoryItem(link);
if (item is InventoryWearable)
{
var w = (InventoryWearable)item;
if (w.WearableType == type)
{
ret.Add(item);
}
}
});
return ret;
}
/// <summary>
/// Resolves inventory links and returns a real inventory item that
/// the link is pointing to
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public InventoryItem RealInventoryItem(InventoryItem item)
{
if (item.IsLink() && Client.Inventory.Store.Contains(item.AssetUUID) && Client.Inventory.Store[item.AssetUUID] is InventoryItem)
{
return (InventoryItem)Client.Inventory.Store[item.AssetUUID];
}
return item;
}
/// <summary>
/// Replaces the current outfit and updates COF links accordingly
/// </summary>
/// <param name="outfit">List of new wearables and attachments that comprise the new outfit</param>
public void ReplaceOutfit(List<InventoryItem> newOutfit)
{
// Resolve inventory links
List<InventoryItem> outfit = new List<InventoryItem>();
foreach (var item in newOutfit)
{
outfit.Add(RealInventoryItem(item));
}
// Remove links to all exiting items
List<UUID> toRemove = new List<UUID>();
ContentLinks().ForEach(item =>
{
if (IsBodyPart(item))
{
WearableType linkType = ((InventoryWearable)RealInventoryItem(item)).WearableType;
bool hasBodyPart = false;
foreach (var newItemTmp in newOutfit)
{
var newItem = RealInventoryItem(newItemTmp);
if (IsBodyPart(newItem))
{
if (((InventoryWearable)newItem).WearableType == linkType)
{
hasBodyPart = true;
break;
}
}
}
if (hasBodyPart)
{
toRemove.Add(item.UUID);
}
}
else
{
toRemove.Add(item.UUID);
}
});
Client.Inventory.Remove(toRemove, null);
// Add links to new items
List<InventoryItem> newItems = outfit.FindAll(item => CanBeWorn(item));
foreach (var item in newItems)
{
AddLink(item);
}
Client.Appearance.ReplaceOutfit(outfit, false);
ThreadPool.QueueUserWorkItem(sync =>
{
Thread.Sleep(2000);
Client.Appearance.RequestSetAppearance(true);
});
}
/// <summary>
/// Add items to current outfit
/// </summary>
/// <param name="item">Item to add</param>
/// <param name="replace">Should existing wearable of the same type be removed</param>
public void AddToOutfit(InventoryItem item, bool replace)
{
AddToOutfit(new List<InventoryItem>(1) { item }, replace);
}
/// <summary>
/// Add items to current outfit
/// </summary>
/// <param name="items">List of items to add</param>
/// <param name="replace">Should existing wearable of the same type be removed</param>
public void AddToOutfit(List<InventoryItem> items, bool replace)
{
List<InventoryItem> current = ContentLinks();
List<UUID> toRemove = new List<UUID>();
// Resolve inventory links and remove wearables of the same type from COF
List<InventoryItem> outfit = new List<InventoryItem>();
foreach (var item in items)
{
InventoryItem realItem = RealInventoryItem(item);
if (realItem is InventoryWearable)
{
foreach (var link in current)
{
var currentItem = RealInventoryItem(link);
if (link.AssetUUID == item.UUID)
{
toRemove.Add(link.UUID);
}
else if (currentItem is InventoryWearable)
{
var w = (InventoryWearable)currentItem;
if (w.WearableType == ((InventoryWearable)realItem).WearableType)
{
toRemove.Add(link.UUID);
}
}
}
}
outfit.Add(realItem);
}
Client.Inventory.Remove(toRemove, null);
// Add links to new items
List<InventoryItem> newItems = outfit.FindAll(item => CanBeWorn(item));
foreach (var item in newItems)
{
AddLink(item);
}
Client.Appearance.AddToOutfit(outfit, replace);
ThreadPool.QueueUserWorkItem(sync =>
{
Thread.Sleep(2000);
Client.Appearance.RequestSetAppearance(true);
});
}
/// <summary>
/// Remove an item from the current outfit
/// </summary>
/// <param name="items">Item to remove</param>
public void RemoveFromOutfit(InventoryItem item)
{
RemoveFromOutfit(new List<InventoryItem>(1) { item });
}
/// <summary>
/// Remove specified items from the current outfit
/// </summary>
/// <param name="items">List of items to remove</param>
public void RemoveFromOutfit(List<InventoryItem> items)
{
// Resolve inventory links
List<InventoryItem> outfit = new List<InventoryItem>();
foreach (var item in items)
{
var realItem = RealInventoryItem(item);
//if (Instance.RLV.AllowDetach(realItem))
//{
outfit.Add(realItem);
//}
}
// Remove links to all items that were removed
List<UUID> toRemove = new List<UUID>();
foreach (InventoryItem item in outfit.FindAll(item => CanBeWorn(item) && !IsBodyPart(item)))
{
toRemove.Add(item.UUID);
}
RemoveLink(toRemove);
Client.Appearance.RemoveFromOutfit(outfit);
}
public bool IsBodyPart(InventoryItem item)
{
var realItem = RealInventoryItem(item);
if (realItem is InventoryWearable)
{
var w = (InventoryWearable)realItem;
var t = w.WearableType;
if (t == WearableType.Shape ||
t == WearableType.Skin ||
t == WearableType.Eyes ||
t == WearableType.Hair)
{
return true;
}
}
return false;
}
/// <summary>
/// Force rebaking textures
/// </summary>
public void RebakeTextures()
{
Client.Appearance.RequestSetAppearance(true);
}
#endregion Public methods
}
}
+169
View File
@@ -0,0 +1,169 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
//using System.Reflection;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace Raindrop
{
public class Grid
{
public string ID = string.Empty;
public string Name = string.Empty;
public string Platform = string.Empty;
public string LoginURI = string.Empty;
public string LoginPage = string.Empty;
public string HelperURI = string.Empty;
public string Website = string.Empty;
public string Support = string.Empty;
public string Register = string.Empty;
public string PasswordURL = string.Empty;
public string Version = "1";
public Grid() { }
public Grid(string ID, string name, string loginURI)
{
this.ID = ID;
this.Name = name;
this.LoginURI = loginURI;
}
public override string ToString()
{
return Name;
}
public static Grid FromOSD(OSD data)
{
if (data == null || data.Type != OSDType.Map) return null;
Grid grid = new Grid();
OSDMap map = (OSDMap)data;
grid.ID = map["gridnick"].AsString();
grid.Name = map["gridname"].AsString();
grid.Platform = map["platform"].AsString();
grid.LoginURI = map["loginuri"].AsString();
grid.LoginPage = map["loginpage"].AsString();
grid.HelperURI = map["helperuri"].AsString();
grid.Website = map["website"].AsString();
grid.Support = map["support"].AsString();
grid.Register = map["register"].AsString();
grid.PasswordURL = map["password"].AsString();
grid.Version = map["version"].AsString();
return grid;
}
}
public class GridManager : IDisposable
{
public List<Grid> Grids;
public GridManager()
{
Grids = new List<Grid>();
}
public void Dispose()
{
}
public void LoadGrids(string datadir)
{
Grids.Clear();
Grids.Add(new Grid("agni", "Second Life (agni)", "https://login.agni.lindenlab.com/cgi-bin/login.cgi"));
Grids.Add(new Grid("aditi", "Second Life Beta (aditi)", "https://login.aditi.lindenlab.com/cgi-bin/login.cgi"));
try
{
string sysGridsFile = Path.Combine(Path.GetDirectoryName(datadir), "grids.xml");
OSDArray sysGrids = (OSDArray)OSDParser.DeserializeLLSDXml(File.ReadAllText(sysGridsFile));
for (int i = 0; i < sysGrids.Count; i++)
{
RegisterGrid(Grid.FromOSD(sysGrids[i]));
}
}
catch (Exception ex)
{
Logger.Log(string.Format("Error loading grid information: {0}", ex.Message), Helpers.LogLevel.Warning);
}
}
public void RegisterGrid(Grid grid)
{
int ix = Grids.FindIndex((Grid g) => { return g.ID == grid.ID; });
if (ix < 0)
{
Grids.Add(grid);
}
else
{
Grids[ix] = grid;
}
}
public Grid this[int ix]
{
get { return Grids[ix]; }
}
public Grid this[string gridID]
{
get
{
foreach (Grid grid in Grids)
{
if (grid.ID == gridID) return grid;
}
throw new KeyNotFoundException();
}
}
public bool KeyExists(string gridID)
{
foreach (Grid grid in Grids)
{
if (grid.ID == gridID) return true;
}
return false;
}
public int Count
{
get { return Grids.Count; }
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 96f21062a49b52b43914d622cebbfb1e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+723
View File
@@ -0,0 +1,723 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if (COGBOT_LIBOMV || USE_STHREADS)
using ThreadPoolUtil;
using Thread = ThreadPoolUtil.Thread;
using ThreadPool = ThreadPoolUtil.ThreadPool;
using Monitor = ThreadPoolUtil.Monitor;
#endif
using System.Threading;
using System.IO;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using System.Collections.Concurrent;
namespace Raindrop
{
#region enums
/// <summary>
/// Enum representing different modes of handling display names
/// </summary>
public enum NameMode : int
{
/// <summary> No display names </summary>
Standard,
/// <summary> Display name followed by (username) if display name is not default </summary>
Smart,
/// <summary> Display name followed by (username) </summary>
OnlyDisplayName,
/// <summary> Only display </summary>
DisplayNameAndUserName,
}
#endregion enums
/// <summary>
/// Manager for looking up avatar names and their caching
/// </summary>
public class NameManager : IDisposable
{
#region public fields and properties
public event EventHandler<UUIDNameReplyEventArgs> NameUpdated;
public NameMode Mode
{
get
{
if (!client.Avatars.DisplayNamesAvailable())
return NameMode.Standard;
return (NameMode)instance.GlobalSettings["display_name_mode"].AsInteger();
}
set
{
instance.GlobalSettings["display_name_mode"] = (int)value;
}
}
#endregion public fields and properties
#region private fields and properties
RaindropInstance instance;
GridClient client { get { return instance.Client; } }
Timer requestTimer;
Timer cacheTimer;
string cacheFileName;
Queue<UUID> requests = new Queue<UUID>();
int MaxNameRequests = 80;
// Queue up name request for this many ms, and send a batch requst
const int REQUEST_DELAY = 100;
// Save name cache after change to names after this many ms
const int CACHE_DELAY = 30000;
// Consider request failed after this many ms
const int MAX_REQ_AGE = 15000;
Dictionary<UUID, AgentDisplayName> names = new Dictionary<UUID, AgentDisplayName>();
Dictionary<UUID, int> activeRequests = new Dictionary<UUID, int>();
ConcurrentQueue<List<UUID>> PendingLookups;
//BlockingQueue<List<UUID>> PendingLookups;
Thread requestThread = null;
Semaphore lookupGate;
bool useRequestThread;
#endregion private fields and properties
#region construction and disposal
public NameManager(RaindropInstance instance)
{
this.instance = instance;
requestTimer = new Timer(MakeRequest, null, Timeout.Infinite, Timeout.Infinite);
cacheTimer = new Timer(SaveCache, null, Timeout.Infinite, Timeout.Infinite);
cacheFileName = Path.Combine(instance.UserDir, "name.cache");
LoadCachedNames();
instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
RegisterEvents(client);
// Mono HTTPWebRequest sucks balls
useRequestThread = instance.MonoRuntime;
if (useRequestThread)
{
PendingLookups = new ConcurrentQueue<List<UUID>>();
lookupGate = new Semaphore(4, 4);
requestThread = new Thread(new ThreadStart(RequestThread));
requestThread.IsBackground = true;
requestThread.Name = "Display Name Request Thread";
requestThread.Start();
}
}
public void Dispose()
{
SaveCache(new object());
if (client != null)
{
DeregisterEvents(client);
}
if (requestTimer != null)
{
requestTimer.Dispose();
requestTimer = null;
}
if (cacheTimer != null)
{
cacheTimer.Dispose();
cacheTimer = null;
}
try
{
if (useRequestThread)
{
//PendingLookups.Close();
if (requestThread != null)
{
if (!requestThread.Join(5 * 1000))
{
requestThread.Abort();
}
requestThread = null;
}
}
}
catch { }
}
#endregion construction and disposal
#region private methods
public void RequestThread()
{
//PendingLookups.Open();
while (true)
{
List<UUID> req = null;
if (!PendingLookups.TryDequeue(/*Timeout.Infinite,*/ out req)) break;
lookupGate.WaitOne(90 * 1000);
client.Avatars.GetDisplayNames(req, (bool success, AgentDisplayName[] names, UUID[] badIDs) =>
{
if (success)
{
ProcessDisplayNames(names);
}
else
{
Logger.Log("Failed fetching display names", Helpers.LogLevel.Warning, client);
}
lookupGate.Release(1);
});
}
}
void RegisterEvents(GridClient c)
{
c.Avatars.UUIDNameReply += new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);
c.Avatars.DisplayNameUpdate += new EventHandler<DisplayNameUpdateEventArgs>(Avatars_DisplayNameUpdate);
}
void DeregisterEvents(GridClient c)
{
c.Avatars.UUIDNameReply -= new EventHandler<UUIDNameReplyEventArgs>(Avatars_UUIDNameReply);
c.Avatars.DisplayNameUpdate -= new EventHandler<DisplayNameUpdateEventArgs>(Avatars_DisplayNameUpdate);
}
DateTime UUIDNameOnly = new DateTime(1970, 9, 4, 10, 0, 0, DateTimeKind.Utc);
void instance_ClientChanged(object sender, ClientChangedEventArgs e)
{
DeregisterEvents(e.OldClient);
RegisterEvents(e.Client);
}
void Avatars_DisplayNameUpdate(object sender, DisplayNameUpdateEventArgs e)
{
lock (names)
{
e.DisplayName.Updated = DateTime.Now;
names[e.DisplayName.ID] = e.DisplayName;
}
Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
ret.Add(e.DisplayName.ID, FormatName(e.DisplayName));
TriggerEvent(ret);
}
void Avatars_UUIDNameReply(object sender, UUIDNameReplyEventArgs e)
{
Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
foreach (KeyValuePair<UUID, string> kvp in e.Names)
{
// Remove from the list of active requests if in UUID only (standard mode)
if (Mode == NameMode.Standard)
{
lock (activeRequests)
{
activeRequests.Remove(kvp.Key);
}
}
lock (names)
{
if (!names.ContainsKey(kvp.Key))
{
names[kvp.Key] = new AgentDisplayName();
names[kvp.Key].ID = kvp.Key;
names[kvp.Key].NextUpdate = UUIDNameOnly;
names[kvp.Key].IsDefaultDisplayName = true;
}
names[kvp.Key].Updated = DateTime.Now;
string[] parts = kvp.Value.Trim().Split(' ');
if (parts.Length == 2)
{
if (InvalidName(names[kvp.Key].DisplayName))
{
names[kvp.Key].DisplayName = string.Format("{0} {1}", parts[0], parts[1]);
}
names[kvp.Key].LegacyFirstName = parts[0];
names[kvp.Key].LegacyLastName = parts[1];
if (names[kvp.Key].LegacyLastName == "Resident")
{
names[kvp.Key].UserName = names[kvp.Key].LegacyFirstName.ToLower();
}
else
{
names[kvp.Key].UserName = string.Format("{0}.{1}", parts[0], parts[1]).ToLower();
}
ret.Add(kvp.Key, FormatName(names[kvp.Key]));
}
}
}
TriggerEvent(ret);
TriggerCacheSave();
}
string FormatName(AgentDisplayName n)
{
switch (Mode)
{
case NameMode.OnlyDisplayName:
return n.DisplayName;
case NameMode.Smart:
if (n.IsDefaultDisplayName)
return n.DisplayName;
else
return string.Format("{0} ({1})", n.DisplayName, n.UserName);
case NameMode.DisplayNameAndUserName:
return string.Format("{0} ({1})", n.DisplayName, n.UserName);
default:
return n.LegacyFullName;
}
}
bool InvalidName(string displayName)
{
if (string.IsNullOrEmpty(displayName) ||
displayName == "???" ||
displayName == RaindropInstance.INCOMPLETE_NAME)
{
return true;
}
return false;
}
void ProcessDisplayNames(AgentDisplayName[] names)
{
Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
foreach (var name in names)
{
// Remove from the list of active requests
lock (activeRequests)
{
activeRequests.Remove(name.ID);
}
if (InvalidName(name.DisplayName)) continue;
ret.Add(name.ID, FormatName(name));
name.Updated = DateTime.Now;
lock (this.names)
{
this.names[name.ID] = name;
}
}
TriggerEvent(ret);
TriggerCacheSave();
}
void MakeRequest(object sync)
{
List<UUID> req = new List<UUID>();
lock (requests)
{
while (requests.Count > 0)
req.Add(requests.Dequeue());
}
if (req.Count > 0)
{
if (Mode == NameMode.Standard || (!client.Avatars.DisplayNamesAvailable()))
{
client.Avatars.RequestAvatarNames(req);
}
else // Use display names
{
if (useRequestThread)
{
PendingLookups.Enqueue(new List<UUID>(req));
}
else
{
client.Avatars.GetDisplayNames(req, (bool success, AgentDisplayName[] names, UUID[] badIDs) =>
{
if (success)
{
ProcessDisplayNames(names);
}
else
{
Logger.Log("Failed fetching display names", Helpers.LogLevel.Warning, client);
}
});
}
}
}
}
void SaveCache(object sync)
{
ThreadPool.QueueUserWorkItem(syncx =>
{
OSDArray namesOSD = new OSDArray(names.Count);
lock (names)
{
foreach (var name in names)
{
namesOSD.Add(name.Value.GetOSD());
}
}
OSDMap cache = new OSDMap(1);
cache["names"] = namesOSD;
byte[] data = OSDParser.SerializeLLSDBinary(cache, false);
Logger.DebugLog(string.Format("Caching {0} avatar names to {1}", namesOSD.Count, cacheFileName));
try
{
File.WriteAllBytes(cacheFileName, data);
}
catch (Exception ex)
{
Logger.Log("Failed to save avatar name cache: ", Helpers.LogLevel.Error, client, ex);
}
});
}
void LoadCachedNames()
{
ThreadPool.QueueUserWorkItem(syncx =>
{
try
{
byte[] data = File.ReadAllBytes(cacheFileName);
OSDMap cache = (OSDMap)OSDParser.DeserializeLLSDBinary(data);
OSDArray namesOSD = (OSDArray)cache["names"];
DateTime now = DateTime.Now;
TimeSpan maxAge = new TimeSpan(48, 0, 0);
NameMode mode = (NameMode)(int)instance.GlobalSettings["display_name_mode"];
lock (names)
{
for (int i = 0; i < namesOSD.Count; i++)
{
AgentDisplayName name = AgentDisplayName.FromOSD(namesOSD[i]);
if (mode == NameMode.Standard || ((now - name.Updated) < maxAge))
{
names[name.ID] = name;
}
}
}
Logger.DebugLog(string.Format("Restored {0} names from the avatar name cache", names.Count));
}
catch (Exception ex)
{
Logger.Log("Failed loading cached avatar names: ", Helpers.LogLevel.Warning, client, ex);
}
});
}
void TriggerEvent(Dictionary<UUID, string> ret)
{
if (NameUpdated == null || ret.Count == 0) return;
try
{
NameUpdated(this, new UUIDNameReplyEventArgs(ret));
}
catch (Exception ex)
{
Logger.Log("Failure in event handler: " + ex.Message, Helpers.LogLevel.Warning, client, ex);
}
}
void TriggerNameRequest()
{
if (requestTimer != null)
{
requestTimer.Change(REQUEST_DELAY, Timeout.Infinite);
}
}
void TriggerCacheSave()
{
if (cacheTimer != null)
{
cacheTimer.Change(CACHE_DELAY, Timeout.Infinite);
}
}
void QueueNameRequest(UUID agentID)
{
// Check if we're already waiting for an answer on this one
lock (activeRequests)
{
if (activeRequests.ContainsKey(agentID))
{
// Logger.Log("Exiting is active " + agentID.ToString(), Helpers.LogLevel.Error);
if (Environment.TickCount - activeRequests[agentID] < MAX_REQ_AGE) // Not timeout yet
{
// Logger.Log("Exiting is active " + agentID.ToString(), Helpers.LogLevel.Error);
return;
}
else
{
// Logger.Log("Continuing, present but expired " + agentID.ToString(), Helpers.LogLevel.Error);
}
}
else
{
// Logger.Log("Not present " + agentID.ToString(), Helpers.LogLevel.Error);
}
// Record time of when we're making this request
activeRequests[agentID] = Environment.TickCount;
}
lock (requests)
{
if (!requests.Contains(agentID))
{
// Logger.Log("Enqueueing " + agentID.ToString(), Helpers.LogLevel.Error);
requests.Enqueue(agentID);
if (requests.Count >= MaxNameRequests && Mode != NameMode.Standard)
{
requestTimer.Change(Timeout.Infinite, Timeout.Infinite);
MakeRequest(this);
}
else
{
TriggerNameRequest();
}
}
}
}
#endregion private methods
#region public methods
/// <summary>
/// Cleans avatar name cache
/// </summary>
public void CleanCache()
{
lock (names)
{
try
{
names.Clear();
File.Delete(cacheFileName);
}
catch { }
}
}
/// <summary>
/// Gets legacy First Last name
/// </summary>
/// <param name="agentID">UUID of the agent</param>
/// <returns></returns>
public string GetLegacyName(UUID agentID)
{
if (agentID == UUID.Zero) return "(???) (???)";
lock (names)
{
if (names.ContainsKey(agentID))
{
return names[agentID].LegacyFullName;
}
}
QueueNameRequest(agentID);
return RaindropInstance.INCOMPLETE_NAME;
}
/// <summary>
/// Gets UserName
/// </summary>
/// <param name="agentID">UUID of the agent</param>
/// <returns></returns>
public string GetUserName(UUID agentID)
{
if (agentID == UUID.Zero) return "(???) (???)";
lock (names)
{
if (names.ContainsKey(agentID))
{
return names[agentID].UserName;
}
}
QueueNameRequest(agentID);
return RaindropInstance.INCOMPLETE_NAME;
}
/// <summary>
/// Gets DisplayName
/// </summary>
/// <param name="agentID">UUID of the agent</param>
/// <returns></returns>
public string GetDisplayName(UUID agentID)
{
if (agentID == UUID.Zero) return "(???) (???)";
lock (names)
{
if (names.ContainsKey(agentID))
{
return names[agentID].DisplayName;
}
}
QueueNameRequest(agentID);
return RaindropInstance.INCOMPLETE_NAME;
}
/// <summary>
/// Get avatar display name, or queue fetching of the name
/// </summary>
/// <param name="agentID">UUID of avatar to lookup</param>
/// <returns>Avatar display name or "Loading..." if not in cache</returns>
public string Get(UUID agentID)
{
if (agentID == UUID.Zero) return "(???) (???)";
lock (names)
{
if (names.ContainsKey(agentID))
{
if (Mode != NameMode.Standard && names[agentID].NextUpdate == UUIDNameOnly)
{
QueueNameRequest(agentID);
}
return FormatName(names[agentID]);
}
}
QueueNameRequest(agentID);
return RaindropInstance.INCOMPLETE_NAME;
}
/// <summary>
/// Get avatar display name, or queue fetching of the name
/// </summary>
/// <param name="agentID">UUID of avatar to lookup</param>
/// <param name="blocking">If true, wait until name is recieved, otherwise return immediately</param>
/// <returns>Avatar display name or "Loading..." if not in cache</returns>
public string Get(UUID agentID, bool blocking)
{
if (!blocking)
Get(agentID);
string name = null;
using (ManualResetEvent gotName = new ManualResetEvent(false))
{
EventHandler<UUIDNameReplyEventArgs> handler = (object sender, UUIDNameReplyEventArgs e) =>
{
if (e.Names.ContainsKey(agentID))
{
name = e.Names[agentID];
gotName.Set();
}
};
NameUpdated += handler;
name = Get(agentID);
if (name == RaindropInstance.INCOMPLETE_NAME)
{
gotName.WaitOne(20 * 1000, false);
}
NameUpdated -= handler;
}
return name;
}
/// <summary>
/// Get avatar display name, or queue fetching of the name
/// </summary>
/// <param name="agentID">UUID of avatar to lookup</param>
/// <param name="defaultValue">If name failed to retrieve, use this</param>
/// <returns>Avatar display name or the default value if not in cache</returns>
public string Get(UUID agentID, string defaultValue)
{
if (Mode == NameMode.Standard)
return defaultValue;
string name = Get(agentID);
if (name == RaindropInstance.INCOMPLETE_NAME)
return defaultValue;
return name;
}
/// <summary>
/// Get avatar display name, or queue fetching of the name
/// </summary>
/// <param name="agentID">UUID of avatar to lookup</param>
/// <param name="blocking">If true, wait until name is recieved, otherwise return immediately</param>
/// <param name="defaultValue">If name failed to retrieve, use this</param>
/// <returns></returns>
public string Get(UUID agentID, bool blocking, string defaultValue)
{
if (Mode == NameMode.Standard)
return defaultValue;
string name = Get(agentID, blocking);
if (name == RaindropInstance.INCOMPLETE_NAME)
return defaultValue;
return name;
}
#endregion public methods
}
}
@@ -0,0 +1,64 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using OpenMetaverse;
namespace Raindrop.Netcom
{
public class ChatSentEventArgs : EventArgs
{
private string message;
private ChatType type;
private int channel;
public ChatSentEventArgs(string message, ChatType type, int channel)
{
this.message = message;
this.type = type;
this.channel = channel;
}
public string Message
{
get { return message; }
}
public ChatType Type
{
get { return type; }
}
public int Channel
{
get { return channel; }
}
}
}
+40
View File
@@ -0,0 +1,40 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
namespace Raindrop.Netcom
{
public enum StartLocationType
{
Home,
Last,
Custom
};
}
@@ -0,0 +1,71 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using OpenMetaverse;
namespace Raindrop.Netcom
{
public class InstantMessageSentEventArgs : EventArgs
{
private string message;
private UUID targetID;
private UUID sessionID;
private DateTime timestamp;
public InstantMessageSentEventArgs(string message, UUID targetID, UUID sessionID, DateTime timestamp)
{
this.message = message;
this.targetID = targetID;
this.sessionID = sessionID;
this.timestamp = timestamp;
}
public string Message
{
get { return message; }
}
public UUID TargetID
{
get { return targetID; }
}
public UUID SessionID
{
get { return sessionID; }
}
public DateTime Timestamp
{
get { return timestamp; }
}
}
}
+133
View File
@@ -0,0 +1,133 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using OpenMetaverse;
namespace Raindrop.Netcom
{
public class LoginOptions
{
private string firstName;
private string lastName;
private string password;
private string version = string.Empty;
private string channel = string.Empty;
private StartLocationType startLocation = StartLocationType.Home;
private string startLocationCustom = string.Empty;
private Grid grid;
private string gridCustomLoginUri = string.Empty;
private LastExecStatus lastExecEvent = LastExecStatus.Normal;
public LoginOptions()
{
}
public static bool IsPasswordMD5(string pass)
{
return pass.Length == 35 && pass.StartsWith("$1$");
}
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
public string FullName
{
get
{
if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
return string.Empty;
else
return firstName + " " + lastName;
}
}
public string Password
{
get { return password; }
set { password = value; }
}
public StartLocationType StartLocation
{
get { return startLocation; }
set { startLocation = value; }
}
public string StartLocationCustom
{
get { return startLocationCustom; }
set { startLocationCustom = value; }
}
public string Channel
{
get { return channel; }
set { channel = value; }
}
public string Version
{
get { return version; }
set { version = value; }
}
public Grid Grid
{
get { return grid; }
set { grid = value; }
}
public string GridCustomLoginUri
{
get { return gridCustomLoginUri; }
set { gridCustomLoginUri = value; }
}
public LastExecStatus LastExecEvent
{
get { return lastExecEvent; }
set { lastExecEvent = value; }
}
}
}
+420
View File
@@ -0,0 +1,420 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using System.Collections.Generic;
using System.ComponentModel;
using OpenMetaverse;
using Raindrop;
using OpenMetaverse.Packets;
namespace Raindrop.Netcom
{
/// <summary>
/// RadegastNetcom is a class built on top of libsecondlife that provides a way to
/// raise events on the proper thread (for GUI apps especially).
/// </summary>
public partial class RaindropNetcom : IDisposable
{
private RaindropInstance instance;
private GridClient client { get { return instance.Client; } }
public LoginOptions loginOptions;
private bool loggingIn = false;
private bool loggedIn = false;
private bool teleporting = false;
private bool agreeToTos = false;
public bool AgreeToTos { get { return agreeToTos; } set { agreeToTos = value; } }
private Grid grid;
public Grid Grid { get { return grid; } }
// NetcomSync is used for raising certain events on the
// GUI/main thread. Useful if you're modifying GUI controls
// in the client app when responding to those events.
//private Control netcomSync;
//we don't use netcomsync or a netcom actually. we just pass all as events to the unitymainthreaddispatcher for now.
#region ClientConnected event
/// <summary>The event subscribers, null of no subscribers</summary>
private EventHandler<EventArgs> m_ClientConnected;
///<summary>Raises the ClientConnected Event</summary>
/// <param name="e">A ClientConnectedEventArgs object containing
/// the old and the new client</param>
protected virtual void OnClientConnected(EventArgs e)
{
EventHandler<EventArgs> handler = m_ClientConnected;
if (handler != null)
handler(this, e);
}
/// <summary>Thread sync lock object</summary>
private readonly object m_ClientConnectedLock = new object();
/// <summary>Raise event delegate</summary>
private delegate void ClientConnectedRaise(EventArgs e);
/// <summary>Raised when the GridClient object in the main Radegast instance is changed</summary>
public event EventHandler<EventArgs> ClientConnected
{
add { lock (m_ClientConnectedLock) { m_ClientConnected += value; } }
remove { lock (m_ClientConnectedLock) { m_ClientConnected -= value; } }
}
#endregion ClientConnected event
public RaindropNetcom(RaindropInstance instance)
{
this.instance = instance;
loginOptions = new LoginOptions();
instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
RegisterClientEvents(client);
}
private void RegisterClientEvents(GridClient client)
{
client.Self.ChatFromSimulator += new EventHandler<ChatEventArgs>(Self_ChatFromSimulator);
client.Self.IM += new EventHandler<InstantMessageEventArgs>(Self_IM);
client.Self.MoneyBalance += new EventHandler<BalanceEventArgs>(Self_MoneyBalance);
client.Self.TeleportProgress += new EventHandler<TeleportEventArgs>(Self_TeleportProgress);
client.Self.AlertMessage += new EventHandler<AlertMessageEventArgs>(Self_AlertMessage);
client.Network.Disconnected += new EventHandler<DisconnectedEventArgs>(Network_Disconnected);
client.Network.LoginProgress += new EventHandler<LoginProgressEventArgs>(Network_LoginProgress);
client.Network.LoggedOut += new EventHandler<LoggedOutEventArgs>(Network_LoggedOut);
}
private void UnregisterClientEvents(GridClient client)
{
client.Self.ChatFromSimulator -= new EventHandler<ChatEventArgs>(Self_ChatFromSimulator);
client.Self.IM -= new EventHandler<InstantMessageEventArgs>(Self_IM);
client.Self.MoneyBalance -= new EventHandler<BalanceEventArgs>(Self_MoneyBalance);
client.Self.TeleportProgress -= new EventHandler<TeleportEventArgs>(Self_TeleportProgress);
client.Self.AlertMessage -= new EventHandler<AlertMessageEventArgs>(Self_AlertMessage);
client.Network.Disconnected -= new EventHandler<DisconnectedEventArgs>(Network_Disconnected);
client.Network.LoginProgress -= new EventHandler<LoginProgressEventArgs>(Network_LoginProgress);
client.Network.LoggedOut -= new EventHandler<LoggedOutEventArgs>(Network_LoggedOut);
}
void instance_ClientChanged(object sender, ClientChangedEventArgs e)
{
UnregisterClientEvents(e.OldClient);
RegisterClientEvents(client);
}
//private bool CanSyncInvoke
//{
// get
// {
// return netcomSync != null && !netcomSync.IsDisposed && netcomSync.IsHandleCreated && netcomSync.InvokeRequired;
// }
//}
public void Dispose()
{
if (client != null)
{
UnregisterClientEvents(client);
}
}
void Self_IM(object sender, InstantMessageEventArgs e)
{
UnityMainThreadDispatcher.Instance().Enqueue(() => {
Logger.DebugLog("netcom callback: Self_IM");
OnInstantMessageReceived(e);
});
//if (CanSyncInvoke)
// netcomSync.BeginInvoke(new OnInstantMessageRaise(OnInstantMessageReceived), new object[] { e });
//else
// OnInstantMessageReceived(e);
}
void Network_LoginProgress(object sender, LoginProgressEventArgs e)
{
if (e.Status == LoginStatus.Success)
{
loggedIn = true;
client.Self.RequestBalance();
if (CanSyncInvoke)
{
netcomSync.BeginInvoke(new ClientConnectedRaise(OnClientConnected), new object[] { EventArgs.Empty });
}
else
{
OnClientConnected(EventArgs.Empty);
}
}
if (e.Status == LoginStatus.Failed)
{
instance.MarkEndExecution();
}
LoginProgressEventArgs ea = new LoginProgressEventArgs(e.Status, e.Message, string.Empty);
if (CanSyncInvoke)
netcomSync.BeginInvoke(new OnClientLoginRaise(OnClientLoginStatus), new object[] { e });
else
OnClientLoginStatus(e);
}
void Network_LoggedOut(object sender, LoggedOutEventArgs e)
{
loggedIn = false;
if (CanSyncInvoke)
netcomSync.BeginInvoke(new OnClientLogoutRaise(OnClientLoggedOut), new object[] { EventArgs.Empty });
else
OnClientLoggedOut(EventArgs.Empty);
}
void Self_TeleportProgress(object sender, TeleportEventArgs e)
{
if (e.Status == TeleportStatus.Finished || e.Status == TeleportStatus.Failed)
teleporting = false;
if (CanSyncInvoke)
netcomSync.BeginInvoke(new OnTeleportStatusRaise(OnTeleportStatusChanged), new object[] { e });
else
OnTeleportStatusChanged(e);
}
private void Self_ChatFromSimulator(object sender, ChatEventArgs e)
{
if (CanSyncInvoke)
netcomSync.BeginInvoke(new OnChatRaise(OnChatReceived), new object[] { e });
else
OnChatReceived(e);
}
void Network_Disconnected(object sender, DisconnectedEventArgs e)
{
loggedIn = false;
instance.MarkEndExecution();
if (CanSyncInvoke)
netcomSync.BeginInvoke(new OnClientDisconnectRaise(OnClientDisconnected), new object[] { e });
else
OnClientDisconnected(e);
}
void Self_MoneyBalance(object sender, BalanceEventArgs e)
{
if (CanSyncInvoke)
netcomSync.BeginInvoke(new OnMoneyBalanceRaise(OnMoneyBalanceUpdated), new object[] { e });
else
OnMoneyBalanceUpdated(e);
}
void Self_AlertMessage(object sender, AlertMessageEventArgs e)
{
if (CanSyncInvoke)
netcomSync.BeginInvoke(new OnAlertMessageRaise(OnAlertMessageReceived), new object[] { e });
else
OnAlertMessageReceived(e);
}
public void Login()
{
loggingIn = true;
// Report crashes only once and not on relogs/reconnects
LastExecStatus execStatus = instance.GetLastExecStatus();
if (!instance.AnotherInstanceRunning() && execStatus != LastExecStatus.Normal && (!instance.ReportedCrash))
{
instance.ReportedCrash = true;
loginOptions.LastExecEvent = execStatus;
Logger.Log("Reporting crash of the last application run to the grid login service", Helpers.LogLevel.Warning);
}
else
{
loginOptions.LastExecEvent = LastExecStatus.Normal;
Logger.Log("Reporting normal shutdown of the last application run to the grid login service", Helpers.LogLevel.Info);
}
instance.MarkStartExecution();
OverrideEventArgs ea = new OverrideEventArgs();
OnClientLoggingIn(ea);
if (ea.Cancel)
{
loggingIn = false;
return;
}
if (string.IsNullOrEmpty(loginOptions.FirstName) ||
string.IsNullOrEmpty(loginOptions.LastName) ||
string.IsNullOrEmpty(loginOptions.Password))
{
OnClientLoginStatus(
new LoginProgressEventArgs(LoginStatus.Failed, "One or more fields are blank.", string.Empty));
}
string startLocation = string.Empty;
switch (loginOptions.StartLocation)
{
case StartLocationType.Home: startLocation = "home"; break;
case StartLocationType.Last: startLocation = "last"; break;
case StartLocationType.Custom:
startLocation = loginOptions.StartLocationCustom.Trim();
StartLocationParser parser = new StartLocationParser(startLocation);
startLocation = NetworkManager.StartLocation(parser.Sim, parser.X, parser.Y, parser.Z);
break;
}
string password;
if (LoginOptions.IsPasswordMD5(loginOptions.Password))
{
password = loginOptions.Password;
}
else
{
if (loginOptions.Password.Length > 16)
{
password = Utils.MD5(loginOptions.Password.Substring(0, 16));
}
else
{
password = Utils.MD5(loginOptions.Password);
}
}
LoginParams loginParams = client.Network.DefaultLoginParams(
loginOptions.FirstName, loginOptions.LastName, password,
loginOptions.Channel, loginOptions.Version);
grid = loginOptions.Grid;
loginParams.Start = startLocation;
loginParams.AgreeToTos = AgreeToTos;
loginParams.URI = grid.LoginURI;
loginParams.LastExecEvent = loginOptions.LastExecEvent;
client.Network.BeginLogin(loginParams);
}
public void Logout()
{
if (!loggedIn)
{
OnClientLoggedOut(EventArgs.Empty);
return;
}
OverrideEventArgs ea = new OverrideEventArgs();
OnClientLoggingOut(ea);
if (ea.Cancel) return;
client.Network.Logout();
}
public void ChatOut(string chat, ChatType type, int channel)
{
if (!loggedIn) return;
client.Self.Chat(chat, channel, type);
OnChatSent(new ChatSentEventArgs(chat, type, channel));
}
public void SendInstantMessage(string message, UUID target, UUID session)
{
if (!loggedIn) return;
client.Self.InstantMessage(
loginOptions.FullName, target, message, session, InstantMessageDialog.MessageFromAgent,
InstantMessageOnline.Online, client.Self.SimPosition, client.Network.CurrentSim.ID, null);
OnInstantMessageSent(new InstantMessageSentEventArgs(message, target, session, DateTime.Now));
}
public void SendIMStartTyping(UUID target, UUID session)
{
if (!loggedIn) return;
client.Self.InstantMessage(
loginOptions.FullName, target, "typing", session, InstantMessageDialog.StartTyping,
InstantMessageOnline.Online, client.Self.SimPosition, client.Network.CurrentSim.ID, null);
}
public void SendIMStopTyping(UUID target, UUID session)
{
if (!loggedIn) return;
client.Self.InstantMessage(
loginOptions.FullName, target, "typing", session, InstantMessageDialog.StopTyping,
InstantMessageOnline.Online, client.Self.SimPosition, client.Network.CurrentSim.ID, null);
}
public void Teleport(string sim, Vector3 coordinates)
{
if (!loggedIn) return;
if (teleporting) return;
TeleportingEventArgs ea = new TeleportingEventArgs(sim, coordinates);
OnTeleporting(ea);
if (ea.Cancel) return;
teleporting = true;
client.Self.Teleport(sim, coordinates);
}
public bool IsLoggingIn
{
get { return loggingIn; }
}
public bool IsLoggedIn
{
get { return loggedIn; }
}
public bool IsTeleporting
{
get { return teleporting; }
}
public LoginOptions LoginOptions
{
get { return loginOptions; }
set { loginOptions = value; }
}
//public Control NetcomSync
//{
// get { return netcomSync; }
// set { netcomSync = value; }
//}
}
}
+127
View File
@@ -0,0 +1,127 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using OpenMetaverse;
namespace Raindrop.Netcom
{
public partial class RaindropNetcom
{
// For the NetcomSync stuff
private delegate void OnClientLoginRaise(LoginProgressEventArgs e);
private delegate void OnClientLogoutRaise(EventArgs e);
private delegate void OnClientDisconnectRaise(DisconnectedEventArgs e);
private delegate void OnChatRaise(ChatEventArgs e);
private delegate void OnInstantMessageRaise(InstantMessageEventArgs e);
private delegate void OnAlertMessageRaise(AlertMessageEventArgs e);
private delegate void OnMoneyBalanceRaise(BalanceEventArgs e);
private delegate void OnTeleportStatusRaise(TeleportEventArgs e);
public event EventHandler<OverrideEventArgs> ClientLoggingIn;
public event EventHandler<LoginProgressEventArgs> ClientLoginStatus;
public event EventHandler<OverrideEventArgs> ClientLoggingOut;
public event EventHandler ClientLoggedOut;
public event EventHandler<DisconnectedEventArgs> ClientDisconnected;
public event EventHandler<ChatEventArgs> ChatReceived;
public event EventHandler<ChatSentEventArgs> ChatSent;
public event EventHandler<InstantMessageEventArgs> InstantMessageReceived;
public event EventHandler<InstantMessageSentEventArgs> InstantMessageSent;
public event EventHandler<TeleportingEventArgs> Teleporting;
public event EventHandler<TeleportEventArgs> TeleportStatusChanged;
public event EventHandler<AlertMessageEventArgs> AlertMessageReceived;
public event EventHandler<BalanceEventArgs> MoneyBalanceUpdated;
protected virtual void OnClientLoggingIn(OverrideEventArgs e)
{
if (ClientLoggingIn != null) ClientLoggingIn(this, e);
}
protected virtual void OnClientLoginStatus(LoginProgressEventArgs e)
{
if (ClientLoginStatus != null) ClientLoginStatus(this, e);
}
protected virtual void OnClientLoggingOut(OverrideEventArgs e)
{
if (ClientLoggingOut != null) ClientLoggingOut(this, e);
}
protected virtual void OnClientLoggedOut(EventArgs e)
{
if (ClientLoggedOut != null) ClientLoggedOut(this, e);
}
protected virtual void OnClientDisconnected(DisconnectedEventArgs e)
{
if (ClientDisconnected != null) ClientDisconnected(this, e);
}
protected virtual void OnChatReceived(ChatEventArgs e)
{
if (ChatReceived != null) ChatReceived(this, e);
}
protected virtual void OnChatSent(ChatSentEventArgs e)
{
if (ChatSent != null) ChatSent(this, e);
}
protected virtual void OnInstantMessageReceived(InstantMessageEventArgs e)
{
if (InstantMessageReceived != null) InstantMessageReceived(this, e);
}
protected virtual void OnInstantMessageSent(InstantMessageSentEventArgs e)
{
if (InstantMessageSent != null) InstantMessageSent(this, e);
}
protected virtual void OnTeleporting(TeleportingEventArgs e)
{
if (Teleporting != null) Teleporting(this, e);
}
protected virtual void OnTeleportStatusChanged(TeleportEventArgs e)
{
if (TeleportStatusChanged != null) TeleportStatusChanged(this, e);
}
protected virtual void OnAlertMessageReceived(AlertMessageEventArgs e)
{
if (AlertMessageReceived != null) AlertMessageReceived(this, e);
}
protected virtual void OnMoneyBalanceUpdated(BalanceEventArgs e)
{
if (MoneyBalanceUpdated != null) MoneyBalanceUpdated(this, e);
}
}
}
@@ -0,0 +1,55 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
namespace Raindrop.Netcom
{
public class OverrideEventArgs : EventArgs
{
private bool _cancel = false;
public OverrideEventArgs()
{
}
public OverrideEventArgs(bool cancel)
{
_cancel = cancel;
}
public bool Cancel
{
get { return _cancel; }
set { _cancel = value; }
}
}
}
@@ -0,0 +1,125 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
namespace Raindrop.Netcom
{
public class StartLocationParser
{
private string location;
public StartLocationParser(string location)
{
if (location == null) throw new Exception("Location cannot be null.");
this.location = location;
}
private string GetSim(string location)
{
if (!location.Contains("/")) return location;
string[] locSplit = location.Split('/');
return locSplit[0];
}
private int GetX(string location)
{
if (!location.Contains("/")) return 128;
string[] locSplit = location.Split('/');
int returnResult;
bool stringToInt = int.TryParse(locSplit[1], out returnResult);
if (stringToInt)
return returnResult;
else
return 128;
}
private int GetY(string location)
{
if (!location.Contains("/")) return 128;
string[] locSplit = location.Split('/');
if (locSplit.Length > 2)
{
int returnResult;
bool stringToInt = int.TryParse(locSplit[2], out returnResult);
if (stringToInt)
return returnResult;
}
return 128;
}
private int GetZ(string location)
{
if (!location.Contains("/")) return 0;
string[] locSplit = location.Split('/');
if (locSplit.Length > 3)
{
int returnResult;
bool stringToInt = int.TryParse(locSplit[3], out returnResult);
if (stringToInt)
return returnResult;
}
return 0;
}
public string Sim
{
get { return GetSim(location); }
}
public int X
{
get { return GetX(location); }
}
public int Y
{
get { return GetY(location); }
}
public int Z
{
get { return GetZ(location); }
}
}
}
@@ -0,0 +1,56 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using OpenMetaverse;
namespace Raindrop.Netcom
{
public class TeleportingEventArgs : OverrideEventArgs
{
private string _sim;
private Vector3 _coordinates;
public TeleportingEventArgs(string sim, Vector3 coordinates) : base()
{
_sim = sim;
_coordinates = coordinates;
}
public string SimName
{
get { return _sim; }
}
public Vector3 Coordinates
{
get { return _coordinates; }
}
}
}
+224 -170
View File
@@ -1,213 +1,267 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LibreMetaverse;
using OpenMetaverse;
//using System.Collections;
//using System.Collections.Generic;
//using UnityEngine;
//using LibreMetaverse;
//using OpenMetaverse;
//using DisruptorUnity3d;
//namespace Raindrop
//{
// //implements (actually, composites) the gridclient
// public class RaindropClient //todo: decouple unity, maybe.
// {
// //static readonly RingBuffer<int> Queue = new RingBuffer<int>(1000);
namespace Raindrop
{
//implements (actually, composites) the gridclient
public class RaindropClient
{
//todo: internal eventbus for raindrop subsystems comms; include ui?
public event Notify LoginCompleted;
public event Notify LoginFailed;
// //todo: internal eventbus for raindrop subsystems comms; include ui?
// public event Notify LoginCompleted;
// public event Notify LoginFailed;
public GridClient Client;
// public GridClient Client;
public enum RaindropState
{
intialise,
connected,
disconnected
// public enum RaindropState
// {
// intialise,
// connected,
// disconnected
}
// }
private RaindropState clientstate;
// private RaindropState clientstate;
private string Username { get; set; }
private string Password { get; set; }
public string configdatapath { get; private set; }
// private readonly object eventLock = new object();
// private List<UUID> avatars_in_sim = new List<UUID>();
// private Global globalRef;
public RaindropClient()
{
clientstate = RaindropState.intialise;
// private string Username { get; set; }
// private string Password { get; set; }
// public string configdatapath { get; private set; }
Client = new GridClient(); // instantiates the GridClient class
// to the global Client object
// public RaindropClient(string appdatapath, Global global)
// {
// globalRef = global;
// //ensure you set the app path first, so that the Setting static prop gets updated before construction of the client instance.
// setConfigPath(appdatapath);
Client.Settings.USE_LLSD_LOGIN = true;
const string AGNI_LOGIN_SERVER = "https://login.agni.lindenlab.com/cgi-bin/login.cgi";
Client.Settings.LOGIN_SERVER = AGNI_LOGIN_SERVER;
// clientstate = RaindropState.intialise;
// Client = new GridClient(); // instantiates the GridClient class
// // to the global Client object
// Client.Settings.USE_LLSD_LOGIN = true;
// const string AGNI_LOGIN_SERVER = "https://login.agni.lindenlab.com/cgi-bin/login.cgi";
// Client.Settings.LOGIN_SERVER = AGNI_LOGIN_SERVER;
// RegisterClientEvents();
// }
RegisterClientEvents();
}
private void RegisterClientEvents()
{
////register events
//Client.Appearance.AgentWearablesReply += Appearance_AgentWearablesReply;
//Client.Appearance.AppearanceSet += Appearance_AppearanceSet;
//Client.Appearance.CachedBakesReply += Appearance_CachedBakesReply;
//Client.Appearance.RebakeAvatarRequested += Appearance_RebakeAvatarRequested;
// private void RegisterClientEvents()
// {
// ////register events
// //Client.Appearance.AgentWearablesReply += Appearance_AgentWearablesReply;
// //Client.Appearance.AppearanceSet += Appearance_AppearanceSet;
// //Client.Appearance.CachedBakesReply += Appearance_CachedBakesReply;
// //Client.Appearance.RebakeAvatarRequested += Appearance_RebakeAvatarRequested;
////local chat
Client.Self.ChatFromSimulator += Self_ChatFromSimulator;
// ////local chat
// Client.Self.ChatFromSimulator += Self_ChatFromSimulator;
////user connected/disconnected
Client.Network.Disconnected += Network_Disconnected;
Client.Network.LoginProgress += Network_LoginProgress;
// ////user connected/disconnected
// Client.Network.Disconnected += Network_Disconnected;
// Client.Network.LoginProgress += Network_LoginProgress;
////grid location update
Client.Grid.CoarseLocationUpdate += Grid_CoarseLocationUpdate;
Client.Network.SimChanged += Network_SimChanged;
// ////grid location update
// Client.Grid.CoarseLocationUpdate += Grid_CoarseLocationUpdate;
// Client.Network.SimChanged += Network_SimChanged;
//log
OpenMetaverse.Logger.OnLogMessage += Logger_OnLogMessage;
}
// //log
// OpenMetaverse.Logger.OnLogMessage += Logger_OnLogMessage;
// }
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);
}
}
//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);
// }
//}
internal void setConfigPath(string app_data_Path)
{
this.configdatapath = app_data_Path;
// internal void setConfigPath(string app_data_Path)
// {
// this.configdatapath = app_data_Path;
// Settings.RESOURCE_DIR = app_data_Path;
// //Client.Settings.ASSET_CACHE_DIR = app_data_Path + "/cache";
// }
}
// private void Network_SimChanged(object sender, SimChangedEventArgs e)
// {
// Debug.Log("Sim was changed.");
// }
private void Network_SimChanged(object sender, SimChangedEventArgs e)
{
throw new System.NotImplementedException();
}
private void Grid_CoarseLocationUpdate(object sender, CoarseLocationUpdateEventArgs e)
{
throw new System.NotImplementedException();
}
private void Network_LoginProgress(object sender, LoginProgressEventArgs e)
{
if (e.Status == LoginStatus.Failed)
{
LoginFailed?.Invoke(); //raise event.
Debug.LogWarning("logging in failed. \n Message: " + e.Message + "fail reason: " + e.FailReason);
}
else if (e.Status == LoginStatus.Success)
{
this.clientstate = RaindropState.connected;
LoginCompleted?.Invoke(); //raise event.
Disk.SaveLoad.saveCred(Username,Password, configdatapath);
// private void Grid_CoarseLocationUpdate(object sender, CoarseLocationUpdateEventArgs e)
// {
Debug.Log("logging in success. \n Message: " + e.Message);
// lock (eventLock)
// {
// if (e.Simulator == Client.Network.CurrentSim)
// {
// foreach (var each in e.NewEntries)
// {
// avatars_in_sim.Add(each);
// }
// foreach (var each in e.RemovedEntries)
// {
// if (avatars_in_sim.Contains(each))
// {
// avatars_in_sim.Remove(each);
// }
// }
// if (e.NewEntries.Count != 0 || e.RemovedEntries.Count != 0)
// {
// Debug.Log("Avatars: " + avatars_in_sim.ToString());
// }
// }
// }
// }
// private void Network_LoginProgress(object sender, LoginProgressEventArgs e)
// {
// if (e.Status == LoginStatus.Failed)
// {
// LoginFailed?.Invoke(); //raise event.
// Debug.LogWarning("logging in failed. \n Message: " + e.Message + "fail reason: " + e.FailReason);
// globalRef.RaindropVM.canvasManager.pushModal(); //error mah boi
// }
// else if (e.Status == LoginStatus.Success)
// {
// this.clientstate = RaindropState.connected;
// //LoginCompleted?.Invoke(); //raise event.
// UnityMainThreadDispatcher.Instance().Enqueue(() =>
// {
// Debug.Log("This is executed from the main thread");
// Debug.Log("Login success ui update");
// globalRef.RaindropVM.canvasManager.popCanvas(); //remove login panel from sight.
// globalRef.RaindropVM.canvasManager.pushCanvas(CanvasType.Game);
// });
// Disk.SaveLoad.saveCred(Username,Password, configdatapath);
// Debug.Log("logging in success. \n Message: " + e.Message);
}
else if (e.Status == LoginStatus.ConnectingToLogin)
{
Debug.Log("ConnectingToLogin. \n Message: " + e.Message);
// }
// else if (e.Status == LoginStatus.ConnectingToLogin)
// {
// //Debug.Log("ConnectingToLogin. \n Message: " + e.Message);
}
else if (e.Status == LoginStatus.ConnectingToSim)
{
Debug.Log("ConnectingToSim. \n Message: " + e.Message);
// }
// else if (e.Status == LoginStatus.ConnectingToSim)
// {
// Debug.Log("ConnectingToSim. \n Message: " + e.Message);
}
else
{
Debug.LogError("logging in not-supported. \n status type: " + e.Status.ToString() + "\n Message: " + e.Message);
}
}
// }
// else
// {
// Debug.LogError("logging in not-supported. \n status type: " + e.Status.ToString() + "\n Message: " + e.Message);
// }
// }
private void Network_Disconnected(object sender, DisconnectedEventArgs e)
{
Debug.Log("Disconnected!");
}
// private void Network_Disconnected(object sender, DisconnectedEventArgs e)
// {
// Debug.Log("Disconnected!");
// }
private void Self_ChatFromSimulator(object sender, ChatEventArgs e)
{
throw new System.NotImplementedException();
}
// private void Self_ChatFromSimulator(object sender, ChatEventArgs e)
// {
// Debug.Log("Chat: " + e.FromName+ " : " + e.Message);
//private void Appearance_RebakeAvatarRequested(object sender, RebakeAvatarTexturesEventArgs e)
//{
// throw new System.NotImplementedException();
//}
// }
//private void Appearance_CachedBakesReply(object sender, AgentCachedBakesReplyEventArgs e)
//{
// throw new System.NotImplementedException();
//}
// //private void Appearance_RebakeAvatarRequested(object sender, RebakeAvatarTexturesEventArgs e)
// //{
// // throw new System.NotImplementedException();
// //}
//private void Appearance_AppearanceSet(object sender, AppearanceSetEventArgs e)
//{
// throw new System.NotImplementedException();
//}
// //private void Appearance_CachedBakesReply(object sender, AgentCachedBakesReplyEventArgs e)
// //{
// // throw new System.NotImplementedException();
// //}
//private void Appearance_AgentWearablesReply(object sender, AgentWearablesReplyEventArgs e)
//{
// throw new System.NotImplementedException();
//}
// //private void Appearance_AppearanceSet(object sender, AppearanceSetEventArgs e)
// //{
// // throw new System.NotImplementedException();
// //}
//connects to SL. username is either format; ie: "firstname lastname" or "Jaken69" are both compaitble.
public void connectTo(string username, string password)
{
// //private void Appearance_AgentWearablesReply(object sender, AgentWearablesReplyEventArgs e)
// //{
// // throw new System.NotImplementedException();
// //}
Username = username;
Password = password;
// //connects to SL. username is either format; ie: "firstname lastname" or "Jaken69" are both compaitble.
// public void connectTo(string username, string password)
// {
// Login to Simulator
string[] _splitname = username.Split();
if (_splitname.Length == 1)
{
var temp = _splitname[0];
_splitname = new string[2];
_splitname[0] = temp;
_splitname[1] = "";
}
else if (_splitname.Length != 2)
{
Debug.LogError("username is not 2 words (tip examples of valid usernames: \'Jake69 Resident\' or \'Jake Aabye\')");
return;
}
// Username = username;
// Password = password;
var lp = new LoginParams(Global.MainRaindropInstance.Client, _splitname[0], _splitname[1], password, "raindropviewer@gmail.com", "RaindropViewer_0.1");
Debug.Log("attempt login with name1 " + _splitname[0] + " name 2 " + _splitname[1] + " password " + password);
Global.MainRaindropInstance.Client.Network.BeginLogin(lp);
// // Login to Simulator
// string[] _splitname = username.Split();
// if (_splitname.Length == 1)
// {
// var temp = _splitname[0];
// _splitname = new string[2];
// _splitname[0] = temp;
// _splitname[1] = "";
// }
// else if (_splitname.Length != 2)
// {
// Debug.LogError("username is not 2 words (tip examples of valid usernames: \'Jake69 Resident\' or \'Jake Aabye\')");
// return;
// }
//UnityClient.Client.Network.Login(lp);
// Logout of simulator
//Client.Network.Logout();
// var lp = new LoginParams(Client, _splitname[0], _splitname[1], password, "raindropviewer@gmail.com", "RaindropViewer_0.1");
// Debug.Log("attempt login with name1 " + _splitname[0] + " name 2 " + _splitname[1] + " password " + password);
// Client.Network.BeginLogin(lp);
}
// //UnityClient.Client.Network.Login(lp);
// // Logout of simulator
// //Client.Network.Logout();
}
}
// }
// }
//}
+12 -12
View File
@@ -1,16 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
namespace Raindrop
{
public delegate void Notify();
//namespace Raindrop
//{
// public delegate void Notify();
class RaindropEvents
{
}
}
// class RaindropEvents
// {
// }
//}
+851
View File
@@ -0,0 +1,851 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
//using Radegast.Commands;
using Raindrop.Netcom;
//using Radegast.Media;
using OpenMetaverse;
using UnityEngine;
using Logger = OpenMetaverse.Logger;
namespace Raindrop
{
public class RaindropInstance
{
#region OnRadegastFormCreated
//Actually this event is never subscribed to!
//public event Action<RadegastForm> RadegastFormCreated;
///// <summary>
///// Triggers the RadegastFormCreated event.
///// this method is called directly by the 'form' when the UI is loaded. the payload is the actual form - eg: formProfile
///// </summary>
//public virtual void OnRadegastFormCreated(RadegastForm radForm)
//{
// if (RadegastFormCreated != null) RadegastFormCreated(radForm);
//}
#endregion
private GridClient client;
private RaindropNetcom netcom;
private StateManager state;
private string app_data_dir;
//private frmMain mainForm; //frmMain is a class that inherits RadegastForm. It seems to be the code-behind of the overall UI, that includes the view and buttons.
private mainUI mainCanvas;
// Singleton, there can be only one instance
private static RaindropInstance globalInstance = null;
public static RaindropInstance GlobalInstance
{
get
{
if (globalInstance == null)
{
globalInstance = new RaindropInstance(new GridClient());
}
return globalInstance;
}
}
/// <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;
private string userDir;
/// <summary>
/// System (not grid!) user's dir
/// </summary>
public string UserDir { get { return userDir; } }
/// <summary>
/// Grid client's user dir for settings and logs
/// </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; } }
private Dictionary<UUID, Group> groups = new Dictionary<UUID, Group>();
public Dictionary<UUID, Group> Groups { get { return groups; } }
private Settings globalSettings;
/// <summary>
/// Global settings for the entire application
/// </summary>
public Settings GlobalSettings { get { return globalSettings; } }
private Settings clientSettings;
/// <summary>
/// Per client settings
/// </summary>
public Settings ClientSettings { get { return clientSettings; } }
public const string INCOMPLETE_NAME = "Loading...";
public readonly bool advancedDebugging = false;
//private PluginManager pluginManager;
///// <summary> Handles loading plugins and scripts</summary>
//public PluginManager PluginManager { get { return pluginManager; } }
//private MediaManager mediaManager;
///// <summary>
///// Radegast media manager for playing streams and in world sounds
///// </summary>
//public MediaManager MediaManager { get { return mediaManager; } }
//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> m_ClientChanged;
///<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 = m_ClientChanged;
if (handler != null)
handler(this, e);
}
/// <summary>Thread sync lock object</summary>
private readonly object m_ClientChangedLock = new object();
/// <summary>Raised when the GridClient object in the main Radegast instance is changed</summary>
public event EventHandler<ClientChangedEventArgs> ClientChanged
{
add { lock (m_ClientChangedLock) { m_ClientChanged += value; } }
remove { lock (m_ClientChangedLock) { m_ClientChanged -= value; } }
}
#endregion ClientChanged event
#region InventoryClipboardUpdated event
/// <summary>The event subscribers, null of no subscribers</summary>
private EventHandler<EventArgs> m_InventoryClipboardUpdated;
///<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 = m_InventoryClipboardUpdated;
if (handler != null)
handler(this, e);
}
/// <summary>Thread sync lock object</summary>
private readonly object m_InventoryClipboardUpdatedLock = new object();
/// <summary>Raised when the GridClient object in the main Radegast instance is changed</summary>
public event EventHandler<EventArgs> InventoryClipboardUpdated
{
add { lock (m_InventoryClipboardUpdatedLock) { m_InventoryClipboardUpdated += value; } }
remove { lock (m_InventoryClipboardUpdatedLock) { m_InventoryClipboardUpdated -= value; } }
}
#endregion InventoryClipboardUpdated event
#endregion Events
public RaindropInstance(GridClient client0)
{
// incase something else calls GlobalInstance while we are loading
globalInstance = this;
app_data_dir = Application.persistentDataPath;
//if (!System.Diagnostics.Debugger.IsAttached)
//{
// Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Application.ThreadException += HandleThreadException;
//}
client = client0;
// Initialize current time zone, and mark when we started
GetWorldTimeZone();
StartupTimeUTC = DateTime.UtcNow;
// Are we running mono?
monoRuntime = Type.GetType("Mono.Runtime") != null;
//Keyboard = new Keyboard();
//Application.AddMessageFilter(Keyboard);
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);
InitializeLoggingAndConfig();
InitializeClient(client);
//rlv = new RLVManager(this);
gridManager = new GridManager();
gridManager.LoadGrids(app_data_dir);
names = new NameManager(this);
COF = new CurrentOutfitFolder(this);
mainCanvas = new mainUI(this);
//mainCanvas.InitializeControls();
//mainCanvas.Load += new EventHandler(mainForm_Load);
//pluginManager = new PluginManager(this);
//pluginManager.ScanAndLoadPlugins();
}
private void InitializeClient(GridClient client)
{
client.Settings.MULTIPLE_SIMS = false;
client.Settings.USE_INTERPOLATION_TIMER = false;
client.Settings.ALWAYS_REQUEST_OBJECTS = true;
client.Settings.ALWAYS_DECODE_OBJECTS = true;
client.Settings.OBJECT_TRACKING = true;
client.Settings.ENABLE_SIMSTATS = true;
client.Settings.FETCH_MISSING_INVENTORY = true;
client.Settings.SEND_AGENT_THROTTLE = true;
client.Settings.SEND_AGENT_UPDATES = true;
client.Settings.STORE_LAND_PATCHES = true;
client.Settings.USE_ASSET_CACHE = true;
client.Settings.ASSET_CACHE_DIR = Path.Combine(userDir, "cache");
client.Assets.Cache.AutoPruneEnabled = false;
client.Assets.Cache.ComputeAssetCacheFilename = ComputeCacheName;
client.Throttle.Total = 5000000f;
client.Settings.THROTTLE_OUTGOING_PACKETS = false;
client.Settings.LOGIN_TIMEOUT = 120 * 1000;
client.Settings.SIMULATOR_TIMEOUT = 180 * 1000;
client.Settings.MAX_CONCURRENT_TEXTURE_DOWNLOADS = 20;
client.Self.Movement.AutoResetControls = false;
client.Self.Movement.UpdateInterval = 250;
RegisterClientEvents(client);
SetClientTag();
}
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);
}
public void SetClientTag()
{
if (GlobalSettings["send_rad_client_tag"])
{
client.Settings.CLIENT_IDENTIFICATION_TAG = new UUID("b748af88-58e2-995b-cf26-9486dea8e830");
}
else
{
client.Settings.CLIENT_IDENTIFICATION_TAG = UUID.Zero;
}
}
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()
{
//TabConsole.DisplayNotificationInChat("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();
}
public void CleanUp()
{
MarkEndExecution();
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 mainForm_Load(object sender, EventArgs e)
{
//pluginManager.StartPlugins();
}
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;
}
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);
}
public void LogClientMessage(string sessioName, string message)
{
if (globalSettings["disable_chat_im_log"]) return;
lock (this)
{
try
{
File.AppendAllText(ChatFileName(sessioName),
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;
}
private void InitializeLoggingAndConfig()
{
try
{
userDir = Path.Combine(app_data_dir , PROGRAMNAME);
if (!Directory.Exists(userDir))
{
Directory.CreateDirectory(userDir);
}
}
catch (Exception)
{
userDir = System.Environment.CurrentDirectory;
};
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 mainUI MainCanvas
{
get { return mainCanvas; }
}
//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 = "RaindropTest_02";
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 app_data_Path)
{
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
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
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a513c3b8d6c8e1b48adc33fd6d665cef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+171
View File
@@ -0,0 +1,171 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using System.Timers;
using OpenMetaverse;
namespace Raindrop
{
public class RaindropMovement : IDisposable
{
private RaindropInstance instance;
private GridClient client { get { return instance.Client; } }
private Timer timer;
private Vector3 forward = new Vector3(1, 0, 0);
private bool turningLeft = false;
private bool turningRight = false;
private bool movingForward = false;
private bool movingBackward = false;
public bool TurningLeft
{
get
{
return turningLeft;
}
set
{
turningLeft = value;
if (value)
{
timer_Elapsed(null, null);
timer.Enabled = true;
}
else
{
timer.Enabled = false;
client.Self.Movement.TurnLeft = false;
client.Self.Movement.SendUpdate(true);
}
}
}
public bool TurningRight
{
get
{
return turningRight;
}
set
{
turningRight = value;
if (value)
{
timer_Elapsed(null, null);
timer.Enabled = true;
}
else
{
timer.Enabled = false;
client.Self.Movement.TurnRight = false;
client.Self.Movement.SendUpdate(true);
}
}
}
public bool MovingForward
{
get
{
return movingForward;
}
set
{
movingForward = value;
if (value)
{
client.Self.Movement.AtPos = true;
client.Self.Movement.SendUpdate(true);
}
else
{
client.Self.Movement.AtPos = false;
client.Self.Movement.SendUpdate(true);
}
}
}
public bool MovingBackward
{
get
{
return movingBackward;
}
set
{
movingBackward = value;
if (value)
{
client.Self.Movement.AtNeg = true;
client.Self.Movement.SendUpdate(true);
}
else
{
client.Self.Movement.AtNeg = false;
client.Self.Movement.SendUpdate(true);
}
}
}
public RaindropMovement(RaindropInstance instance)
{
this.instance = instance;
timer = new System.Timers.Timer(100);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Enabled = false;
}
public void Dispose()
{
timer.Enabled = false;
timer.Dispose();
timer = null;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
float delta = (float)timer.Interval / 1000f;
if (turningLeft)
{
client.Self.Movement.TurnLeft = true;
client.Self.Movement.BodyRotation = client.Self.Movement.BodyRotation * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, delta);
client.Self.Movement.SendUpdate(true);
}
else if (turningRight)
{
client.Self.Movement.TurnRight = true;
client.Self.Movement.BodyRotation = client.Self.Movement.BodyRotation * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, -delta);
client.Self.Movement.SendUpdate(true);
}
}
}
}
+17
View File
@@ -0,0 +1,17 @@
{
"name": "RaindropUnity",
"rootNamespace": "",
"references": [
"GUID:b6ef318018e211441b43da945a1caf13",
"GUID:1364d97af688c264f94c622d729b2059"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0e5c96f0601ad834f84ded85be85a608
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+417
View File
@@ -0,0 +1,417 @@
//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Xml;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using System.Drawing;
//using System.Web.Script.Serialization;
using System.ComponentModel;
using SixLabors.ImageSharp;
namespace Raindrop
{
public class Settings : IDictionary<string, OSD>
{
private string SettingsFile;
private OSDMap SettingsData;
public delegate void SettingChangedCallback(object sender, SettingsEventArgs e);
public event SettingChangedCallback OnSettingChanged;
public static readonly Dictionary<string, FontSetting> DefaultFontSettings = new Dictionary<string, FontSetting>()
{
{"Normal", new FontSetting {
Name = "Normal",
ForeColor = SystemColors.ControlText,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"StatusBlue", new FontSetting {
Name = "StatusBlue",
ForeColor = Color.Blue,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"StatusDarkBlue", new FontSetting {
Name = "StatusDarkBlue",
ForeColor = Color.DarkBlue,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"LindenChat", new FontSetting {
Name = "LindenChat",
ForeColor = Color.DarkGreen,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"ObjectChat", new FontSetting {
Name = "ObjectChat",
ForeColor = Color.DarkCyan,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"StartupTitle", new FontSetting {
Name = "StartupTitle",
ForeColor = SystemColors.ControlText,
BackColor = Color.Transparent,
Font = new Font(FontSetting.DefaultFont, FontStyle.Bold),
}},
{"Alert", new FontSetting {
Name = "Alert",
ForeColor = Color.DarkRed,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"Error", new FontSetting {
Name = "Error",
ForeColor = Color.Red,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"OwnerSay", new FontSetting {
Name = "OwnerSay",
ForeColor = Color.DarkGoldenrod,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"Timestamp", new FontSetting {
Name = "Timestamp",
ForeColor = SystemColors.GrayText,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"Name", new FontSetting {
Name = "Name",
ForeColor = SystemColors.ControlText,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"Notification", new FontSetting {
Name = "Notification",
ForeColor = SystemColors.ControlText,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"IncomingIM", new FontSetting {
Name = "IncomingIM",
ForeColor = SystemColors.ControlText,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"OutgoingIM", new FontSetting {
Name = "OutgoingIM",
ForeColor = SystemColors.ControlText,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"Emote", new FontSetting {
Name = "Emote",
ForeColor = SystemColors.ControlText,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
{"Self", new FontSetting {
Name = "Self",
ForeColor = SystemColors.ControlText,
BackColor = Color.Transparent,
Font = FontSetting.DefaultFont,
}},
};
public class FontSetting
{
[ScriptIgnoreAttribute]
public static readonly Font DefaultFont = new Font(FontFamily.GenericSansSerif, 8.0f);
[ScriptIgnoreAttribute]
public Font Font;
[ScriptIgnoreAttribute]
public Color ForeColor;
[ScriptIgnoreAttribute]
public Color BackColor;
public String Name;
public string ForeColorString
{
get
{
if (ForeColor != null)
{
return ColorTranslator.ToHtml(ForeColor);
}
else
{
return ColorTranslator.ToHtml(SystemColors.ControlText);
}
}
set
{
ForeColor = ColorTranslator.FromHtml(value);
}
}
public string BackColorString
{
get
{
if (BackColor != null)
{
return ColorTranslator.ToHtml(BackColor);
}
else
{
return ColorTranslator.ToHtml(SystemColors.ControlText);
}
}
set
{
BackColor = ColorTranslator.FromHtml(value);
}
}
public string FontString
{
get
{
if (this.Font != null)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(Font));
return converter.ConvertToString(this.Font);
}
else
{
return null;
}
}
set
{
try
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(Font));
this.Font = converter.ConvertFromString(value) as Font;
}
catch (Exception)
{
this.Font = DefaultFont;
}
}
}
public override string ToString()
{
return Name;
}
}
public Settings(string fileName)
{
SettingsFile = fileName;
try
{
string xml = File.ReadAllText(SettingsFile);
SettingsData = (OSDMap)OSDParser.DeserializeLLSDXml(xml);
}
catch
{
Logger.DebugLog("Failed opening settings file: " + fileName);
SettingsData = new OSDMap();
Save();
}
}
public void Save()
{
try
{
File.WriteAllText(SettingsFile, SerializeLLSDXmlStringFormated(SettingsData));
}
catch (Exception ex)
{
Logger.Log("Failed saving settings", Helpers.LogLevel.Warning, ex);
}
}
public static string SerializeLLSDXmlStringFormated(OSD data)
{
using (StringWriter sw = new StringWriter())
{
using (XmlTextWriter writer = new XmlTextWriter(sw))
{
writer.Formatting = Formatting.Indented;
writer.Indentation = 4;
writer.IndentChar = ' ';
writer.WriteStartElement(String.Empty, "llsd", String.Empty);
OSDParser.SerializeLLSDXmlElement(writer, data);
writer.WriteEndElement();
writer.Close();
return sw.ToString();
}
}
}
private void FireEvent(string key, OSD val)
{
if (OnSettingChanged != null)
{
try { OnSettingChanged(this, new SettingsEventArgs(key, val)); }
catch (Exception) { }
}
}
#region IDictionary Implementation
public int Count { get { return SettingsData.Count; } }
public bool IsReadOnly { get { return false; } }
public ICollection<string> Keys { get { return SettingsData.Keys; } }
public ICollection<OSD> Values { get { return SettingsData.Values; } }
public OSD this[string key]
{
get
{
return SettingsData[key];
}
set
{
if (string.IsNullOrEmpty(key))
{
Logger.DebugLog("Warning: trying to set an emprty setting: " + Environment.StackTrace.ToString());
}
else
{
SettingsData[key] = value;
FireEvent(key, value);
Save();
}
}
}
public bool ContainsKey(string key)
{
return SettingsData.ContainsKey(key);
}
public void Add(string key, OSD llsd)
{
SettingsData.Add(key, llsd);
FireEvent(key, llsd);
Save();
}
public void Add(KeyValuePair<string, OSD> kvp)
{
SettingsData.Add(kvp.Key, kvp.Value);
FireEvent(kvp.Key, kvp.Value);
Save();
}
public bool Remove(string key)
{
bool ret = SettingsData.Remove(key);
FireEvent(key, null);
Save();
return ret;
}
public bool TryGetValue(string key, out OSD llsd)
{
return SettingsData.TryGetValue(key, out llsd);
}
public void Clear()
{
SettingsData.Clear();
Save();
}
public bool Contains(KeyValuePair<string, OSD> kvp)
{
// This is a bizarre function... we don't really implement it
// properly, hopefully no one wants to use it
return SettingsData.ContainsKey(kvp.Key);
}
public void CopyTo(KeyValuePair<string, OSD>[] array, int index)
{
throw new NotImplementedException();
}
public bool Remove(KeyValuePair<string, OSD> kvp)
{
bool ret = SettingsData.Remove(kvp.Key);
FireEvent(kvp.Key, null);
Save();
return ret;
}
public System.Collections.IDictionaryEnumerator GetEnumerator()
{
return SettingsData.GetEnumerator();
}
IEnumerator<KeyValuePair<string, OSD>> IEnumerable<KeyValuePair<string, OSD>>.GetEnumerator()
{
return null;
}
IEnumerator IEnumerable.GetEnumerator()
{
return SettingsData.GetEnumerator();
}
#endregion IDictionary Implementation
}
public class SettingsEventArgs : EventArgs
{
public string Key = string.Empty;
public OSD Value = new OSD();
public SettingsEventArgs(string key, OSD val)
{
Key = key;
Value = val;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4d006287ccb09804583f81650c8c71b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
+42
View File
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Raindrop;
public class Global : MonoBehaviour
{
//public GameObject CanvasManagerObject;
public CanvasManager CanvasManagerRef;
//this static-new is like a globally accessible instance without a singleton! :)
public RaindropInstance MainRaindropInstance;
//this one manages the viewmodels and the stacking of UI modals.
public RaindropViewManager RaindropVM;
public string app_data_Path { get; private set; }
private void Awake()
{
CanvasManagerRef= FindObjectOfType<CanvasManager>();
//initialise your 'statics'
//Get the path of the Game data folder
//app_data_Path = Application.persistentDataPath;
//Output the Game data path to the console
//Debug.Log("dataPath : " + app_data_Path);
//raindropinstance seems tightly coupled with the applicaiton lifecycle; it seems essentially a subset of the app lifecycle in fact.
//make sure you supply the app directory.
MainRaindropInstance = RaindropInstance.GlobalInstance;
//RaindropInstance.GlobalInstance.setAppDataDir(app_data_Path);
RaindropVM = new RaindropViewManager(MainRaindropInstance);
}
}
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Raindrop
{
public enum CanvasType
{
Login,
Game
}
public class RaindropViewManager
{
public CanvasManager canvasManager;
//manages all child Viewmodels
public RaindropViewManager(RaindropInstance instance)
{
//Debug.Log("VM manager setup ok");
//subscribe all events from raindropclient
//Client.LoginCompleted += MainRaindropInstance_LoginCompleted;
//Client.LoginFailed += MainRaindropInstance_LoginFailed;
}
//register the canvas manager which is in a GO, who has the responsibility of flipping pages.
//public void registerWithRaindropClient(CanvasManager canvasManager)
//{
// this.canvasManager = canvasManager;
// //start up the initial login panel
// pushLoginView();
//}
private void pushLoginView()
{
canvasManager.pushCanvas(CanvasType.Login);
}
//private void MainRaindropInstance_LoginFailed()
//{
// Debug.Log("failed login TODO: why?");
//}
private void showFailedLoginModal()
{
throw new NotImplementedException();
}
//private void MainRaindropInstance_LoginCompleted()
//{
// cm.popCanvas();//this lince causes error, as the function was called from the login thread!
// cm.pushCanvas(CanvasType.Game);
// //showSuccessLoginModal();
//}
private void removeLoginView()
{
throw new NotImplementedException();
}
private void showSuccessLoginModal()
{
throw new NotImplementedException();
}
}
}
@@ -11,6 +11,8 @@ public class CanvasManager : Singleton<CanvasManager>
//CanvasIdentifier lastActiveCanvas;
public Stack<CanvasIdentifier> activeCanvasStack = new Stack<CanvasIdentifier>();
public Global Globalref;
protected override void Awake()
{
@@ -20,7 +22,7 @@ public class CanvasManager : Singleton<CanvasManager>
pushCanvas(CanvasType.Login);
//canvas manager (attached to the UI GO) should register with the globals. so that the globals can acess them
Global.RaindropVM.registerWithRaindropClient(this);
//Globalref.RaindropVM.registerWithRaindropClient(this);
}
public void pushCanvas(CanvasType _type)
@@ -52,10 +54,15 @@ public class CanvasManager : Singleton<CanvasManager>
var lastActiveCanvas = activeCanvasStack.Peek();
if (lastActiveCanvas != null)
{
lastActiveCanvas.gameObject.SetActive(false);
lastActiveCanvas.gameObject.SetActive(false); //this lince causes error, as the function was called from the login thread!
activeCanvasStack.Pop();
}
}
internal void pushModal()
{
throw new NotImplementedException();
}
}
@@ -1,4 +1,5 @@
using OpenMetaverse;
using Raindrop;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
@@ -8,6 +9,10 @@ using UnityWeld.Binding;
[Binding]
public class LoginVM : MonoBehaviour, INotifyPropertyChanged
{
public Global globalRef;
private RaindropInstance instance;
private RaindropNetcom netcom { get { return instance.Netcom; } }
#region state
@@ -116,9 +121,25 @@ public class LoginVM : MonoBehaviour, INotifyPropertyChanged
void Start()
{
initialise();
Global.MainRaindropInstance.LoginCompleted += cb_LoginCompleted;
Global.MainRaindropInstance.LoginFailed += cb_LoginFailed;
}
private void AddNetcomEvents()
{
netcom.ClientLoggingIn += new EventHandler<OverrideEventArgs>(netcom_ClientLoggingIn);
netcom.ClientLoginStatus += new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);
netcom.ClientLoggingOut += new EventHandler<OverrideEventArgs>(netcom_ClientLoggingOut);
netcom.ClientLoggedOut += new EventHandler(netcom_ClientLoggedOut);
}
private void RemoveNetcomEvents()
{
netcom.ClientLoggingIn -= new EventHandler<OverrideEventArgs>(netcom_ClientLoggingIn);
netcom.ClientLoginStatus -= new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);
netcom.ClientLoggingOut -= new EventHandler<OverrideEventArgs>(netcom_ClientLoggingOut);
netcom.ClientLoggedOut -= new EventHandler(netcom_ClientLoggedOut);
}
private void cb_LoginFailed()
@@ -174,7 +195,7 @@ public class LoginVM : MonoBehaviour, INotifyPropertyChanged
Debug.LogError("loggin button but username and password are not defined!");
return;
}
Global.MainRaindropInstance.connectTo(Username,Password);
globalRef.MainRaindropInstance.connectTo(Username,Password);
}
@@ -184,7 +205,7 @@ public class LoginVM : MonoBehaviour, INotifyPropertyChanged
Debug.Log("logout btn");
// Logout of simulator
Global.MainRaindropInstance.Client.Network.Logout();
globalRef.MainRaindropInstance.Client.Network.Logout();
}
#endregion
+32
View File
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Raindrop.Netcom;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Assets;
namespace Raindrop
{
public class mainUI
{
private RaindropInstance raindropInstance;
public mainUI(RaindropInstance raindropInstance)
{
this.raindropInstance = raindropInstance;
// Callbacks
netcom.ClientLoginStatus += new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);
netcom.ClientLoggedOut += new EventHandler(netcom_ClientLoggedOut);
netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
instance.Names.NameUpdated += new EventHandler<UUIDNameReplyEventArgs>(Names_NameUpdated);
}
public object instance { get; private set; }
}
}
File diff suppressed because it is too large Load Diff
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3c58dd02bac207f4185512ab84eea324
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+332 -1
View File
@@ -123,6 +123,82 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &26288764
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 26288765}
- component: {fileID: 26288767}
- component: {fileID: 26288766}
m_Layer: 5
m_Name: Overlaydebug
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!224 &26288765
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 26288764}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 267083071}
m_Father: {fileID: 904771131}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 461.74963, y: -300.6742}
m_SizeDelta: {x: -923.4992, y: -601.3484}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &26288766
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 26288764}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0.392}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &26288767
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 26288764}
m_CullTransparentMesh: 1
--- !u!1 &38931173
GameObject:
m_ObjectHideFlags: 0
@@ -142,7 +218,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &38931174
RectTransform:
m_ObjectHideFlags: 0
@@ -427,6 +503,122 @@ MonoBehaviour:
m_PersistentCalls:
m_Calls: []
m_IsOn: 1
--- !u!1 &267083070
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 267083071}
- component: {fileID: 267083075}
- component: {fileID: 267083074}
- component: {fileID: 267083073}
- component: {fileID: 267083072}
m_Layer: 5
m_Name: Panel
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &267083071
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 267083070}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 1597224912}
m_Father: {fileID: 26288765}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 0}
m_AnchorMax: {x: 1, y: 0}
m_AnchoredPosition: {x: -457.23755, y: 191.93365}
m_SizeDelta: {x: 914.4751, y: 383.8673}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &267083072
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 267083070}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f003e7629ecbbdb4c9867c281c3c59c9, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &267083073
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 267083070}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Padding:
m_Left: 0
m_Right: 0
m_Top: 0
m_Bottom: 0
m_ChildAlignment: 0
m_Spacing: 0
m_ChildForceExpandWidth: 1
m_ChildForceExpandHeight: 1
m_ChildControlWidth: 0
m_ChildControlHeight: 0
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
--- !u!114 &267083074
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 267083070}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0.392}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &267083075
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 267083070}
m_CullTransparentMesh: 1
--- !u!1 &289478450
GameObject:
m_ObjectHideFlags: 0
@@ -2227,6 +2419,7 @@ RectTransform:
m_Children:
- {fileID: 1910810518}
- {fileID: 1090573972}
- {fileID: 26288765}
m_Father: {fileID: 0}
m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -2247,6 +2440,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 5759aa2a69d06bf42bc000d03390227e, type: 3}
m_Name:
m_EditorClassIdentifier:
Globalref: {fileID: 0}
--- !u!1 &936677284
GameObject:
m_ObjectHideFlags: 0
@@ -2555,6 +2749,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: c2eeaa71c61350f46902f312854272c9, type: 3}
m_Name:
m_EditorClassIdentifier:
globalRef: {fileID: 0}
--- !u!114 &1090573975
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -3690,6 +3885,140 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1421356640}
m_CullTransparentMesh: 1
--- !u!1 &1597224911
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1597224912}
- component: {fileID: 1597224914}
- component: {fileID: 1597224913}
m_Layer: 5
m_Name: LocationText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1597224912
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1597224911}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 267083071}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 240.7321, y: -42.3337}
m_SizeDelta: {x: 481.4642, y: 84.6674}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1597224913
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1597224911}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: New Text
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 36
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 1
m_VerticalAlignment: 256
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!222 &1597224914
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1597224911}
m_CullTransparentMesh: 1
--- !u!1 &1603377539
GameObject:
m_ObjectHideFlags: 0
@@ -4403,6 +4732,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 55c6aede8bf73ca48b10f0d9e2e771f0, type: 3}
m_Name:
m_EditorClassIdentifier:
CanvasManagerRef: {fileID: 904771132}
--- !u!1 &1889936407
GameObject:
m_ObjectHideFlags: 0
@@ -4573,6 +4903,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: c2eeaa71c61350f46902f312854272c9, type: 3}
m_Name:
m_EditorClassIdentifier:
globalRef: {fileID: 0}
--- !u!114 &1910810522
MonoBehaviour:
m_ObjectHideFlags: 0
+23
View File
@@ -0,0 +1,23 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Raindrop.Tests
{
[TestFixture()]
class RaindropTests
{
[Test()]
public void LoginTest()
{
RaindropClient MainRaindropInstance;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 646de89141f469245ace3f66a81cce73
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+2 -1
View File
@@ -4,7 +4,8 @@
"references": [
"UnityEngine.TestRunner",
"UnityEditor.TestRunner",
"LibreMetaverseAssembly"
"LibreMetaverseAssembly",
"RaindropUnity"
],
"includePlatforms": [],
"excludePlatforms": [],
-32
View File
@@ -1,32 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Raindrop;
public class Global : MonoBehaviour
{
//this static-new is like a globally accessible instance without a singleton! :)
public static RaindropClient MainRaindropInstance = new RaindropClient();
//this one manages the viewmodels and the stacking of UI modals.
public static RaindropViewManager RaindropVM = new RaindropViewManager();
public string app_data_Path { get; private set; }
private void Awake()
{
//initialise your 'statics'
//Get the path of the Game data folder
app_data_Path = Application.persistentDataPath;
//Output the Game data path to the console
Debug.Log("dataPath : " + app_data_Path);
MainRaindropInstance.setConfigPath(app_data_Path);
}
}
-70
View File
@@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Raindrop
{
public enum CanvasType
{
Login,
Game
}
public class RaindropViewManager
{
public CanvasManager cm;
//manages all child Viewmodels
public RaindropViewManager()
{
//Debug.Log("VM manager setup ok");
//subscribe all events from raindropclient
Global.MainRaindropInstance.LoginCompleted += MainRaindropInstance_LoginCompleted;
Global.MainRaindropInstance.LoginFailed += MainRaindropInstance_LoginFailed;
}
//register the canvas manager which is in a GO, who has the responsibility of flipping pages.
public void registerWithRaindropClient(CanvasManager canvasManager)
{
cm = canvasManager;
//start up the initial login panel
pushLoginView();
}
private void pushLoginView()
{
cm.pushCanvas(CanvasType.Login);
}
private void MainRaindropInstance_LoginFailed()
{
Debug.Log("failed login TODO: why?");
}
private void showFailedLoginModal()
{
throw new NotImplementedException();
}
private void MainRaindropInstance_LoginCompleted()
{
cm.popCanvas();
cm.pushCanvas(CanvasType.Game);
//showSuccessLoginModal();
}
private void removeLoginView()
{
throw new NotImplementedException();
}
private void showSuccessLoginModal()
{
throw new NotImplementedException();
}
}
}
+133
View File
@@ -0,0 +1,133 @@
/*
Copyright 2015 Pim de Witte All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading.Tasks;
/// Author: Pim de Witte (pimdewitte.com) and contributors, https://github.com/PimDeWitte/UnityMainThreadDispatcher
/// <summary>
/// A thread-safe class which holds a queue with actions to execute on the next Update() method. It can be used to make calls to the main thread for
/// things such as UI Manipulation in Unity. It was developed for use in combination with the Firebase Unity plugin, which uses separate threads for event handling
/// </summary>
public class UnityMainThreadDispatcher : MonoBehaviour
{
private static readonly Queue<Action> _executionQueue = new Queue<Action>();
public void Update()
{
lock (_executionQueue)
{
while (_executionQueue.Count > 0)
{
_executionQueue.Dequeue().Invoke();
}
}
}
/// <summary>
/// Locks the queue and adds the IEnumerator to the queue
/// </summary>
/// <param name="action">IEnumerator function that will be executed from the main thread.</param>
public void Enqueue(IEnumerator action)
{
lock (_executionQueue)
{
_executionQueue.Enqueue(() => {
StartCoroutine(action);
});
}
}
/// <summary>
/// Locks the queue and adds the Action to the queue
/// </summary>
/// <param name="action">function that will be executed from the main thread.</param>
public void Enqueue(Action action)
{
Enqueue(ActionWrapper(action));
}
/// <summary>
/// Locks the queue and adds the Action to the queue, returning a Task which is completed when the action completes
/// </summary>
/// <param name="action">function that will be executed from the main thread.</param>
/// <returns>A Task that can be awaited until the action completes</returns>
public Task EnqueueAsync(Action action)
{
var tcs = new TaskCompletionSource<bool>();
void WrappedAction()
{
try
{
action();
tcs.TrySetResult(true);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
}
Enqueue(ActionWrapper(WrappedAction));
return tcs.Task;
}
IEnumerator ActionWrapper(Action a)
{
a();
yield return null;
}
private static UnityMainThreadDispatcher _instance = null;
public static bool Exists()
{
return _instance != null;
}
public static UnityMainThreadDispatcher Instance()
{
if (!Exists())
{
throw new Exception("UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.");
}
return _instance;
}
void Awake()
{
if (_instance == null)
{
_instance = this;
DontDestroyOnLoad(this.gameObject);
}
}
void OnDestroy()
{
_instance = null;
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 518a7b51b6ca76b4aa067bd054208dd9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+471
View File
@@ -0,0 +1,471 @@
<llsd>
<array>
<!-- Second Life -->
<map>
<key>gridnick</key>
<string>agni</string>
<key>gridname</key>
<string>Second Life (agni)</string>
<key>platform</key>
<string>SecondLife</string>
<key>loginuri</key>
<string>https://login.agni.lindenlab.com/cgi-bin/login.cgi</string>
<key>loginpage</key>
<string>http://secondlife.com/app/login/?channel=Second+Life+Release</string>
<key>helperuri</key>
<string>https://secondlife.com/helpers/</string>
<key>website</key>
<string>http://secondlife.com/</string>
<key>support</key>
<string>http://secondlife.com/support/</string>
<key>register</key>
<string>http://secondlife.com/registration/</string>
<key>password</key>
<string>http://secondlife.com/account/request.php</string>
<key>version</key>
<string>0</string>
</map>
<!-- Second Life Beta -->
<map>
<key>gridnick</key>
<string>aditi</string>
<key>gridname</key>
<string>Second Life Beta (aditi)</string>
<key>platform</key>
<string>SecondLife</string>
<key>loginuri</key>
<string>https://login.aditi.lindenlab.com/cgi-bin/login.cgi</string>
<key>loginpage</key>
<string>http://secondlife.com/app/login/?channel=Second+Life+Beta</string>
<key>helperuri</key>
<string>http://aditi-secondlife.webdev.lindenlab.com/helpers/</string>
<key>website</key>
<string>http://secondlife.com/</string>
<key>support</key>
<string>http://secondlife.com/support/</string>
<key>register</key>
<string>http://secondlife.com/registration/</string>
<key>password</key>
<string>http://secondlife.com/account/request.php</string>
<key>version</key>
<string>1</string>
</map>
<!-- Metropolis -->
<map>
<key>gridnick</key>
<string>metropolis</string>
<key>gridname</key>
<string>Metropolis Metaversum</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://hypergrid.org:8002/</string>
<key>loginpage</key>
<string>http://metropolis.hypergrid.org</string>
<key>helperuri</key>
<string>http://metropolis.hypergrid.org/currency/helper/</string>
<key>website</key>
<string>http://metropolis.hypergrid.org</string>
<key>support</key>
<string>http://metropolis.hypergrid.org</string>
<key>register</key>
<string>http://metropolis.hypergrid.org/oswi.php</string>
<key>password</key>
<string>http://metropolis.hypergrid.org/oswi.php</string>
<key>version</key>
<string>1</string>
</map>
<!-- OSGrid -->
<map>
<key>gridnick</key>
<string>osgrid</string>
<key>gridname</key>
<string>OSGrid</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://login.osgrid.org/</string>
<key>loginpage</key>
<string>http://osgrid.org/loginscreen.php</string>
<key>helperuri</key>
<string>http://osgrid.org/</string>
<key>website</key>
<string>http://osgrid.org/</string>
<key>support</key>
<string>http://osgrid.org/</string>
<key>register</key>
<string>http://osgrid.org/elgg/account/register.php</string>
<key>password</key>
<string>http://osgrid.org/elgg/account/forgotten_password.php</string>
<key>version</key>
<string>1</string>
</map>
<!-- ReactionGrid -->
<map>
<key>gridnick</key>
<string>reactiongrid</string>
<key>gridname</key>
<string>ReactionGrid</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://reactiongrid.com:8008/</string>
<key>loginpage</key>
<string>http://gsquared.info/portal</string>
<key>website</key>
<string>http://reactiongrid.com/Default.aspx</string>
<key>support</key>
<string>http://reactiongrid.com/Support.aspx</string>
<key>register</key>
<string>http://reactiongrid.com/Register.aspx</string>
<key>password</key>
<string>http://reactiongrid.com/Support/ResetPassword.aspx</string>
<key>version</key>
<string>0</string>
</map>
<!-- 3rd Rock Grid -->
<map>
<key>gridnick</key>
<string>3rdrock</string>
<key>gridname</key>
<string>3rd Rock Grid</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://grid.3rdrockgrid.com:8002/</string>
<key>loginpage</key>
<string>http://3rdrockgrid.com/startpage.php</string>
<key>helperuri</key>
<string>http://3rdrockgrid.com/main/rg_files/wr/</string>
<key>website</key>
<string>http://3rdrockgrid.com/</string>
<key>register</key>
<string>http://www.3rdrockgrid.com/main/index.php?option=com_comprofiler&amp;task=registers</string>
<key>password</key>
<string>http://www.3rdrockgrid.com/main/index.php?option=com_comprofiler&amp;task=lostPassword</string>
<key>support</key>
<string>http://3rdrockgrid.com/</string>
<key>version</key>
<string>0</string>
</map>
<!-- SirinHGpole -->
<map>
<key>gridnick</key>
<string>sirinhgpole</string>
<key>gridname</key>
<string>SirinHGpole</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://hg.sirinhgpole.com:8002/</string>
<key>loginpage</key>
<string></string>
<key>helperuri</key>
<string></string>
<key>website</key>
<string></string>
<key>register</key>
<string></string>
<key>password</key>
<string></string>
<key>support</key>
<string></string>
<key>version</key>
<string>0</string>
</map>
<!-- InWorldz -->
<map>
<key>gridname</key>
<string>Inworldz</string>
<key>gridnick</key>
<string>inworldz</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://inworldz.com:8002/</string>
<key>loginpage</key>
<string>http://inworldz.com/welcome</string>
<key>helperuri</key>
<string>http://inworldz.com/</string>
<key>password</key>
<string>http://inworldz.com/wpassword</string>
<key>register</key>
<string>http://inworldz.com/register</string>
<key>support</key>
<string>http://inworldz.com/help</string>
<key>website</key>
<string>http://inworldz.com/about/</string>
<key>version</key>
<string>0</string>
</map>
<!-- Metavers Francophone FrancoGrid -->
<map>
<key>gridnick</key>
<string>francogrid</string>
<key>gridname</key>
<string>Francogrid</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://login.francogrid.org/</string>
<key>loginpage</key>
<string>http://viewer.francogrid.org/</string>
<key>helperuri</key>
<string>http://helper.main.francogrid.org/</string>
<key>website</key>
<string>http:/francogrid.org/</string>
<key>support</key>
<string>http:/francogrid.org/aide</string>
<key>register</key>
<string>http:/francogrid.org/user/register</string>
<key>password</key>
<string>http:/francogrid.org/user/password</string>
<key>version</key>
<string>0</string>
</map>
<!-- Legend City Online -->
<map>
<key>gridnick</key>
<string>legendcityonline</string>
<key>gridname</key>
<string>Legend City Online</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://login.legendcityonline.com</string>
<key>loginpage</key>
<string>http://www.legendcityonline.com/welcome.php</string>
<key>helperuri</key>
<string>https://secure.legendcityonline.com/</string>
<key>website</key>
<string>http://www.legendcityonline.com/</string>
<key>support</key>
<string>http://www.legendcityonline.com/</string>
<key>register</key>
<string>http://www.legendcityonline.com/</string>
<key>password</key>
<string>http://www.legendcityonline.com/</string>
<key>version</key>
<string>0</string>
</map>
<!-- WorldSimTerra -->
<map>
<key>gridnick</key>
<string>worldsimterra</string>
<key>gridname</key>
<string>WorldSimTerra</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://wsterra.com:8002</string>
<key>loginpage</key>
<string>http://wsterra.com/log.php</string>
<key>helperuri</key>
<string>http://wsterra.com/</string>
<key>website</key>
<string>http://www.worldsimterra.com/</string>
<key>support</key>
<string>http://www.worldsimterra.com/</string>
<key>register</key>
<string>http://www.worldsimterra.com/</string>
<key>password</key>
<string>http://www.worldsimterra.com/</string>
<key>version</key>
<string>0</string>
</map>
<!-- Your Alternative Life -->
<map>
<key>gridnick</key>
<string>youralternativelife</string>
<key>gridname</key>
<string>Your Alternative Life</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://grid01.from-ne.com:8002/</string>
<key>loginpage</key>
<string>http://grid01.from-ne.com/tios/loginscreen3.php</string>
<key>helperuri</key>
<string>http://grid01.from-ne.com/tios/services/</string>
<key>website</key>
<string>http://www.youralternativelife.com</string>
<key>support</key>
<string>http://www.youralternativelife.com</string>
<key>register</key>
<string>http://www.youralternativelife.com</string>
<key>password</key>
<string>http://www.youralternativelife.com</string>
<key>version</key>
<string>0</string>
</map>
<!-- The New World Grid -->
<map>
<key>gridnick</key>
<string>thenewworldgrid</string>
<key>gridname</key>
<string>The New World Grid</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://grid.newworldgrid.com:8002/</string>
<key>loginpage</key>
<string>http://account.newworldgrid.com/loginscreen.php</string>
<key>helperuri</key>
<string>http://account.newworldgrid.com/</string>
<key>website</key>
<string>http://www.newworldgrid.com/</string>
<key>support</key>
<string>http://www.newworldgrid.com/</string>
<key>register</key>
<string>http://www.newworldgrid.com/register</string>
<key>password</key>
<string>http://account.newworldgrid.com/</string>
<key>version</key>
<string>0</string>
</map>
<!-- Cyberlandia -->
<map>
<key>gridnick</key>
<string>cyberlandia</string>
<key>gridname</key>
<string>Cyberlandia</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://grid.cyberlandia.net:8002</string>
<key>loginpage</key>
<string></string>
<key>helperuri</key>
<string></string>
<key>website</key>
<string>http://www.cyberlandia.net</string>
<key>version</key>
<string>0</string>
</map>
<!-- The Gor Grid -->
<map>
<key>gridnick</key>
<string>thegorgrid</string>
<key>gridname</key>
<string>The Gor Grid</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://thegorgrid.com:8002</string>
<key>loginpage</key>
<string>http://thegorgrid.com/loginscreen.php</string>
<key>website</key>
<string>http://thegorgrid.com/</string>
<key>register</key>
<string>http://thegorgrid.com/index.php?page=create</string>
<key>password</key>
<string>http://thegorgrid.com/index.php?page=change</string>
<key>version</key>
<string>0</string>
</map>
<!-- GiantGrid -->
<map>
<key>gridnick</key>
<string>giantgrid</string>
<key>gridname</key>
<string>GiantGrid</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://Gianttest.no-ip.biz:8002/</string>
<key>loginpage</key>
<string>http://gianttest.no-ip.biz:80/gridsplash?method=login</string>
<key>helperuri</key>
<string>http://gianttest.no-ip.biz/giantmap/</string>
<key>version</key>
<string>0</string>
</map>
<!-- Local Host -->
<map>
<key>gridnick</key>
<string>localhost</string>
<key>gridname</key>
<string>Local Host</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://127.0.0.1:9000/</string>
<key>loginpage</key>
<string />
<key>helperuri</key>
<string>http://127.0.0.1:9000/</string>
<key>version</key>
<string>1</string>
</map>
<!-- Local Host -->
<map>
<key>gridnick</key>
<string>gridproxy</string>
<key>gridname</key>
<string>Grid Proxy</string>
<key>platform</key>
<string>OpenSim</string>
<key>loginuri</key>
<string>http://127.0.0.1:8080/</string>
<key>loginpage</key>
<string />
<key>helperuri</key>
<string>http://127.0.0.1:8080/</string>
<key>version</key>
<string>1</string>
</map>
</array>
</llsd>
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bfaa316973c5d774593d35cb9ee33169
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: