Update LibreMetavese and add support for ResetParcelAcccessLists
This commit is contained in:
parent
8f79b49495
commit
b890fdc54b
421 changed files with 51141 additions and 631 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2016, openmetaverse.co
|
* Copyright (c) 2006-2016, openmetaverse.co
|
||||||
* Copyright (c) 2021-2022, Sjofn LLC.
|
* Copyright (c) 2021-2025, Sjofn LLC.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* - Redistribution and use in source and binary forms, with or without
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
|
|
@ -418,8 +418,7 @@ namespace OpenMetaverse.StructuredData
|
||||||
{
|
{
|
||||||
if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute)))
|
if (!Attribute.IsDefined(field, typeof(NonSerializedAttribute)))
|
||||||
{
|
{
|
||||||
OSD serializedField;
|
if (serialized.TryGetValue(field.Name, out var serializedField))
|
||||||
if (serialized.TryGetValue(field.Name, out serializedField))
|
|
||||||
field.SetValue(obj, ToObject(field.FieldType, serializedField));
|
field.SetValue(obj, ToObject(field.FieldType, serializedField));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -433,8 +432,8 @@ namespace OpenMetaverse.StructuredData
|
||||||
{
|
{
|
||||||
private readonly bool _mBool;
|
private readonly bool _mBool;
|
||||||
|
|
||||||
private static readonly byte[] trueBinary = { 0x31 };
|
private static readonly byte[] TrueBinary = { 0x31 };
|
||||||
private static readonly byte[] falseBinary = { 0x30 };
|
private static readonly byte[] FalseBinary = { 0x30 };
|
||||||
|
|
||||||
public override OSDType Type => OSDType.Boolean;
|
public override OSDType Type => OSDType.Boolean;
|
||||||
|
|
||||||
|
|
@ -447,7 +446,7 @@ namespace OpenMetaverse.StructuredData
|
||||||
public override int AsInteger() { return _mBool ? 1 : 0; }
|
public override int AsInteger() { return _mBool ? 1 : 0; }
|
||||||
public override double AsReal() { return _mBool ? 1d : 0d; }
|
public override double AsReal() { return _mBool ? 1d : 0d; }
|
||||||
public override string AsString() { return _mBool ? "1" : "0"; }
|
public override string AsString() { return _mBool ? "1" : "0"; }
|
||||||
public override byte[] AsBinary() { return _mBool ? trueBinary : falseBinary; }
|
public override byte[] AsBinary() { return _mBool ? TrueBinary : FalseBinary; }
|
||||||
public override OSD Copy() { return new OSDBoolean(_mBool); }
|
public override OSD Copy() { return new OSDBoolean(_mBool); }
|
||||||
|
|
||||||
public override string ToString() { return AsString(); }
|
public override string ToString() { return AsString(); }
|
||||||
|
|
@ -596,58 +595,50 @@ namespace OpenMetaverse.StructuredData
|
||||||
|
|
||||||
public override int AsInteger()
|
public override int AsInteger()
|
||||||
{
|
{
|
||||||
double dbl;
|
if (double.TryParse(_mString, out var dbl))
|
||||||
if (double.TryParse(_mString, out dbl))
|
|
||||||
return (int)Math.Floor(dbl);
|
return (int)Math.Floor(dbl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override uint AsUInteger()
|
public override uint AsUInteger()
|
||||||
{
|
{
|
||||||
double dbl;
|
if (double.TryParse(_mString, out var dbl))
|
||||||
if (double.TryParse(_mString, out dbl))
|
|
||||||
return (uint)Math.Floor(dbl);
|
return (uint)Math.Floor(dbl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override long AsLong()
|
public override long AsLong()
|
||||||
{
|
{
|
||||||
double dbl;
|
if (double.TryParse(_mString, out var dbl))
|
||||||
if (double.TryParse(_mString, out dbl))
|
|
||||||
return (long)Math.Floor(dbl);
|
return (long)Math.Floor(dbl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ulong AsULong()
|
public override ulong AsULong()
|
||||||
{
|
{
|
||||||
double dbl;
|
if (double.TryParse(_mString, out var dbl))
|
||||||
if (double.TryParse(_mString, out dbl))
|
|
||||||
return (ulong)Math.Floor(dbl);
|
return (ulong)Math.Floor(dbl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double AsReal()
|
public override double AsReal()
|
||||||
{
|
{
|
||||||
double dbl;
|
return double.TryParse(_mString, out var dbl) ? dbl : 0d;
|
||||||
return double.TryParse(_mString, out dbl) ? dbl : 0d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string AsString() { return _mString; }
|
public override string AsString() { return _mString; }
|
||||||
public override byte[] AsBinary() { return Encoding.UTF8.GetBytes(_mString); }
|
public override byte[] AsBinary() { return Encoding.UTF8.GetBytes(_mString); }
|
||||||
public override UUID AsUUID()
|
public override UUID AsUUID()
|
||||||
{
|
{
|
||||||
UUID uuid;
|
return UUID.TryParse(_mString, out var uuid) ? uuid : UUID.Zero;
|
||||||
return UUID.TryParse(_mString, out uuid) ? uuid : UUID.Zero;
|
|
||||||
}
|
}
|
||||||
public override DateTime AsDate()
|
public override DateTime AsDate()
|
||||||
{
|
{
|
||||||
DateTime dt;
|
return DateTime.TryParse(_mString, out var dt) ? dt : Utils.Epoch;
|
||||||
return DateTime.TryParse(_mString, out dt) ? dt : Utils.Epoch;
|
|
||||||
}
|
}
|
||||||
public override Uri AsUri()
|
public override Uri AsUri()
|
||||||
{
|
{
|
||||||
Uri uri;
|
return Uri.TryCreate(_mString, UriKind.RelativeOrAbsolute, out var uri) ? uri : null;
|
||||||
return Uri.TryCreate(_mString, UriKind.RelativeOrAbsolute, out uri) ? uri : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() { return AsString(); }
|
public override string ToString() { return AsString(); }
|
||||||
|
|
@ -900,12 +891,8 @@ namespace OpenMetaverse.StructuredData
|
||||||
|
|
||||||
public OSD this[string key]
|
public OSD this[string key]
|
||||||
{
|
{
|
||||||
get
|
get => _mMap.TryGetValue(key, out var llsd) ? llsd : new OSD();
|
||||||
{
|
set => _mMap[key] = value;
|
||||||
OSD llsd;
|
|
||||||
return _mMap.TryGetValue(key, out llsd) ? llsd : new OSD();
|
|
||||||
}
|
|
||||||
set { _mMap[key] = value; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ContainsKey(string key)
|
public bool ContainsKey(string key)
|
||||||
|
|
@ -940,9 +927,7 @@ namespace OpenMetaverse.StructuredData
|
||||||
|
|
||||||
public bool Contains(KeyValuePair<string, OSD> kvp)
|
public bool Contains(KeyValuePair<string, OSD> kvp)
|
||||||
{
|
{
|
||||||
// This is a bizarre function... we don't really implement it
|
return _mMap.Contains(kvp);
|
||||||
// properly, hopefully no one wants to use it
|
|
||||||
return _mMap.ContainsKey(kvp.Key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyTo(KeyValuePair<string, OSD>[] array, int index)
|
public void CopyTo(KeyValuePair<string, OSD>[] array, int index)
|
||||||
|
|
|
||||||
|
|
@ -1127,7 +1127,7 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Packs to 32-bit unsigned integers in to a 64-bit unsigned integer
|
/// Packs two 32-bit unsigned integers in to a 64-bit unsigned integer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="a">The left-hand (or X) value</param>
|
/// <param name="a">The left-hand (or X) value</param>
|
||||||
/// <param name="b">The right-hand (or Y) value</param>
|
/// <param name="b">The right-hand (or Y) value</param>
|
||||||
|
|
|
||||||
|
|
@ -1253,6 +1253,8 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
#endregion Callbacks
|
#endregion Callbacks
|
||||||
|
|
||||||
|
private const string AGENT_PROFILE_CAP = "AgentProfile";
|
||||||
|
|
||||||
/// <summary>Reference to the GridClient instance</summary>
|
/// <summary>Reference to the GridClient instance</summary>
|
||||||
private readonly GridClient Client;
|
private readonly GridClient Client;
|
||||||
/// <summary>Used for movement and camera tracking</summary>
|
/// <summary>Used for movement and camera tracking</summary>
|
||||||
|
|
@ -1269,7 +1271,7 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
|
|
||||||
/// <summary>Your (client) avatars <see cref="UUID"/></summary>
|
/// <summary>Your (client) avatar's <see cref="UUID"/></summary>
|
||||||
/// <remarks>"client", "agent", and "avatar" all represent the same thing</remarks>
|
/// <remarks>"client", "agent", and "avatar" all represent the same thing</remarks>
|
||||||
public UUID AgentID { get; private set; }
|
public UUID AgentID { get; private set; }
|
||||||
|
|
||||||
|
|
@ -1491,6 +1493,7 @@ namespace OpenMetaverse
|
||||||
private readonly ManualResetEvent teleportEvent = new ManualResetEvent(false);
|
private readonly ManualResetEvent teleportEvent = new ManualResetEvent(false);
|
||||||
private uint heightWidthGenCounter;
|
private uint heightWidthGenCounter;
|
||||||
private readonly Dictionary<UUID, AssetGesture> gestureCache = new Dictionary<UUID, AssetGesture>();
|
private readonly Dictionary<UUID, AssetGesture> gestureCache = new Dictionary<UUID, AssetGesture>();
|
||||||
|
|
||||||
#endregion Private Members
|
#endregion Private Members
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1566,41 +1569,144 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Chat and instant messages
|
#region Chat and instant messages
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum size in bytes of chat messages
|
||||||
|
/// </summary>
|
||||||
|
public const int MaxChatMessageSize = 1023;
|
||||||
|
|
||||||
protected int message_chunk_group_id = 0; // a int that starts at 1 goes upto 500 (then back to 1)
|
/// <summary>
|
||||||
|
/// Maximum size in bytes of script dialog labels
|
||||||
|
/// </summary>
|
||||||
|
public const int MaxScriptDialogLabelSize = 254;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Splits a multi-byte string into parts of at most <paramref name="splitSizeInBytes"/> bytes. Attempts to avoid
|
||||||
|
/// splitting multi-byte characters (like UTF-8) to preserve integrity. Useful for chunked string processing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The input string to split. May contain multi-byte characters (e.g., UTF-8 text).</param>
|
||||||
|
/// <param name="splitSizeInBytes">Maximum byte size per part of the split string. Must be greater than 0.</param>
|
||||||
|
/// <param name="maxParts">Maximum number of parts to create. Defaults to <see cref="int.MaxValue"/> if unspecified.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="List{T}"/> of strings, each part limited to <paramref name="splitSizeInBytes"/> bytes or less.
|
||||||
|
/// Total parts do not exceed <paramref name="maxParts"/>. Excessive parts over <paramref name="maxParts"/> are discarded.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="Exception">
|
||||||
|
/// Thrown if <paramref name="splitSizeInBytes"/> is less than 1, as splitting below 1 byte is not possible.
|
||||||
|
/// </exception>
|
||||||
|
private static List<string> SplitMultibyteString(string message, int splitSizeInBytes, int maxParts = int.MaxValue)
|
||||||
|
{
|
||||||
|
if (splitSizeInBytes < 1)
|
||||||
|
{
|
||||||
|
throw new Exception("Split size must be at least 1 byte");
|
||||||
|
}
|
||||||
|
if (message.Length == 0)
|
||||||
|
{
|
||||||
|
return new List<string>()
|
||||||
|
{
|
||||||
|
string.Empty
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var messageParts = new List<string>();
|
||||||
|
var messageBytes = System.Text.Encoding.UTF8.GetBytes(message);
|
||||||
|
var messageBytesOffset = 0;
|
||||||
|
|
||||||
|
while (messageParts.Count < maxParts && messageBytesOffset < messageBytes.Length)
|
||||||
|
{
|
||||||
|
var partEndOffset = Math.Min(messageBytesOffset + splitSizeInBytes, messageBytes.Length);
|
||||||
|
if (partEndOffset < messageBytes.Length)
|
||||||
|
{
|
||||||
|
// Starting at the desired split point (previous split point offset + splitSizeInBytes),
|
||||||
|
// iterate backwards, checking each byte until we find a byte that is not a continuation
|
||||||
|
// byte (0x80-0xBF).
|
||||||
|
// See: https://en.wikipedia.org/wiki/UTF-8#Byte_map
|
||||||
|
while (partEndOffset > messageBytesOffset)
|
||||||
|
{
|
||||||
|
var currentByte = messageBytes[partEndOffset];
|
||||||
|
if(currentByte < 0x80 || currentByte > 0xBF)
|
||||||
|
{
|
||||||
|
// The current byte of the message is not a continuation byte and we can split the message here.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
partEndOffset--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partEndOffset == messageBytesOffset)
|
||||||
|
{
|
||||||
|
// Edge case where we're forced to split the multi-byte character, such as when splitSizeInBytes is 1
|
||||||
|
partEndOffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newMessagePart = System.Text.Encoding.UTF8.GetString(
|
||||||
|
messageBytes,
|
||||||
|
messageBytesOffset, partEndOffset - messageBytesOffset
|
||||||
|
);
|
||||||
|
messageParts.Add(newMessagePart);
|
||||||
|
|
||||||
|
messageBytesOffset = partEndOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageParts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send a text message from the Agent to the Simulator on a negative channel via ScriptDialogReplyPacket
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">A <see cref="string"/> containing the message. Messages longer
|
||||||
|
/// than <see cref="MaxScriptDialogLabelSize"/> bytes will be truncated to <see cref="MaxScriptDialogLabelSize"/>
|
||||||
|
/// bytes.</param>
|
||||||
|
/// <param name="channel">The channel to send the message on</param>
|
||||||
|
private void ChatOnNegativeChannel(string message, int channel)
|
||||||
|
{
|
||||||
|
var messageChunks = SplitMultibyteString(message, MaxScriptDialogLabelSize, 1);
|
||||||
|
|
||||||
|
foreach (var messageChunk in messageChunks)
|
||||||
|
{
|
||||||
|
var chatPacket = new ScriptDialogReplyPacket
|
||||||
|
{
|
||||||
|
AgentData =
|
||||||
|
{
|
||||||
|
AgentID = AgentID,
|
||||||
|
SessionID = Client.Self.SessionID
|
||||||
|
},
|
||||||
|
Data =
|
||||||
|
{
|
||||||
|
ObjectID = AgentID,
|
||||||
|
ChatChannel = channel,
|
||||||
|
ButtonIndex = 0,
|
||||||
|
ButtonLabel = Utils.StringToBytes(messageChunk)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Client.Network.SendPacket(chatPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send a text message from the Agent to the Simulator
|
/// Send a text message from the Agent to the Simulator
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">A <see cref="string"/> containing the message</param>
|
/// <param name="message">A <see cref="string"/> containing the message</param>
|
||||||
/// <param name="channel">The channel to send the message on, 0 is the public channel. Channels above 0
|
/// <param name="channel">The channel to send the message on, 0 is the public channel. Messages
|
||||||
/// can be used however only scripts listening on the specified channel will see the message</param>
|
/// sent on non-negative channels longer than <see cref="MaxChatMessageSize"/> bytes will be split
|
||||||
|
/// and sent in chunks of at most <see cref="MaxChatMessageSize"/> bytes. Messages on negative
|
||||||
|
/// channels will be truncated to at most <see cref="MaxScriptDialogLabelSize"/> bytes and chat
|
||||||
|
/// type will be ignored.</param>
|
||||||
/// <param name="type">Denotes the type of message being sent, shout, whisper, etc.</param>
|
/// <param name="type">Denotes the type of message being sent, shout, whisper, etc.</param>
|
||||||
/// <param name="allow_split_message">Enables large messages to be split into chunks of 900 with [CHUNKGROUPID|CHUNKID|TOTALCHUNKS] at the start</param>
|
/// <param name="splitLargeMessages">Allows splitting of long messages into multiple chat messages if true,
|
||||||
/// <param name="hide_chunk_grouping">Hides [CHUNKGROUPID|CHUNKID|TOTALCHUNKS] at the start of chunked messages</param>
|
/// otherwise long messages will be truncated to their maximum size.</param>
|
||||||
public void Chat(string message, int channel, ChatType type,bool allow_split_message=true,bool hide_chunk_grouping=true)
|
public void Chat(string message, int channel, ChatType type, bool splitLargeMessages = true)
|
||||||
{
|
{
|
||||||
if ((message.Length > 900) && (allow_split_message == true))
|
if (channel < 0)
|
||||||
{
|
{
|
||||||
int group_id = message_chunk_group_id;
|
ChatOnNegativeChannel(message, channel);
|
||||||
message_chunk_group_id++;
|
return;
|
||||||
if (message_chunk_group_id > 500) { message_chunk_group_id = 1; }
|
|
||||||
string[] chunks = message.SplitBy(900).ToArray();
|
|
||||||
int chunkid = 1;
|
|
||||||
foreach(string chunk in chunks)
|
|
||||||
{
|
|
||||||
string chunk_grouping = "";
|
|
||||||
if(hide_chunk_grouping == false)
|
|
||||||
{
|
|
||||||
chunk_grouping = $"[{group_id}|{chunkid}|{chunks.Length}]";
|
|
||||||
}
|
}
|
||||||
Chat($"{chunk_grouping}{chunk}", channel, type, false);
|
|
||||||
chunkid++;
|
var messageChunks = SplitMultibyteString(message, MaxChatMessageSize, splitLargeMessages ? int.MaxValue : 1);
|
||||||
}
|
foreach (var messageChunk in messageChunks)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ChatFromViewerPacket chat = new ChatFromViewerPacket
|
var chatPacket = new ChatFromViewerPacket
|
||||||
{
|
{
|
||||||
AgentData =
|
AgentData =
|
||||||
{
|
{
|
||||||
|
|
@ -1610,11 +1716,11 @@ namespace OpenMetaverse
|
||||||
ChatData =
|
ChatData =
|
||||||
{
|
{
|
||||||
Channel = channel,
|
Channel = channel,
|
||||||
Message = Utils.StringToBytes(message),
|
Message = Utils.StringToBytes(messageChunk),
|
||||||
Type = (byte) type
|
Type = (byte) type
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Client.Network.SendPacket(chat);
|
Client.Network.SendPacket(chatPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1722,12 +1828,21 @@ namespace OpenMetaverse
|
||||||
InstantMessageDialog dialog, InstantMessageOnline offline, Vector3 position, UUID regionID,
|
InstantMessageDialog dialog, InstantMessageOnline offline, Vector3 position, UUID regionID,
|
||||||
byte[] binaryBucket)
|
byte[] binaryBucket)
|
||||||
{
|
{
|
||||||
if (target != UUID.Zero)
|
if (target == UUID.Zero)
|
||||||
|
{
|
||||||
|
Logger.Log($"Suppressing instant message \"{message}\" to UUID.Zero", Helpers.LogLevel.Error, Client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var messageParts = SplitMultibyteString(message, MaxChatMessageSize);
|
||||||
|
foreach (var messagePart in messageParts)
|
||||||
{
|
{
|
||||||
ImprovedInstantMessagePacket im = new ImprovedInstantMessagePacket();
|
ImprovedInstantMessagePacket im = new ImprovedInstantMessagePacket();
|
||||||
|
|
||||||
if (imSessionID.Equals(UUID.Zero) || imSessionID.Equals(AgentID))
|
if (imSessionID.Equals(UUID.Zero) || imSessionID.Equals(AgentID))
|
||||||
|
{
|
||||||
imSessionID = AgentID.Equals(target) ? AgentID : target ^ AgentID;
|
imSessionID = AgentID.Equals(target) ? AgentID : target ^ AgentID;
|
||||||
|
}
|
||||||
|
|
||||||
im.AgentData.AgentID = Client.Self.AgentID;
|
im.AgentData.AgentID = Client.Self.AgentID;
|
||||||
im.AgentData.SessionID = Client.Self.SessionID;
|
im.AgentData.SessionID = Client.Self.SessionID;
|
||||||
|
|
@ -1736,7 +1851,7 @@ namespace OpenMetaverse
|
||||||
im.MessageBlock.FromAgentName = Utils.StringToBytes(fromName);
|
im.MessageBlock.FromAgentName = Utils.StringToBytes(fromName);
|
||||||
im.MessageBlock.FromGroup = false;
|
im.MessageBlock.FromGroup = false;
|
||||||
im.MessageBlock.ID = imSessionID;
|
im.MessageBlock.ID = imSessionID;
|
||||||
im.MessageBlock.Message = Utils.StringToBytes(message);
|
im.MessageBlock.Message = Utils.StringToBytes(messagePart);
|
||||||
im.MessageBlock.Offline = (byte)offline;
|
im.MessageBlock.Offline = (byte)offline;
|
||||||
im.MessageBlock.ToAgentID = target;
|
im.MessageBlock.ToAgentID = target;
|
||||||
|
|
||||||
|
|
@ -1750,11 +1865,6 @@ namespace OpenMetaverse
|
||||||
// Send the message
|
// Send the message
|
||||||
Client.Network.SendPacket(im);
|
Client.Network.SendPacket(im);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Log($"Suppressing instant message \"{message}\" to UUID.Zero",
|
|
||||||
Helpers.LogLevel.Error, Client);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1777,7 +1887,15 @@ namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
lock (GroupChatSessions.Dictionary)
|
lock (GroupChatSessions.Dictionary)
|
||||||
{
|
{
|
||||||
if (GroupChatSessions.ContainsKey(groupID))
|
if (!GroupChatSessions.ContainsKey(groupID))
|
||||||
|
{
|
||||||
|
Logger.Log("No Active group chat session appears to exist, use RequestJoinGroupChat() to join one",
|
||||||
|
Helpers.LogLevel.Error, Client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var messageChunks = SplitMultibyteString(message, MaxChatMessageSize);
|
||||||
|
foreach (var messageChunk in messageChunks)
|
||||||
{
|
{
|
||||||
ImprovedInstantMessagePacket im = new ImprovedInstantMessagePacket
|
ImprovedInstantMessagePacket im = new ImprovedInstantMessagePacket
|
||||||
{
|
{
|
||||||
|
|
@ -1791,7 +1909,7 @@ namespace OpenMetaverse
|
||||||
Dialog = (byte) InstantMessageDialog.SessionSend,
|
Dialog = (byte) InstantMessageDialog.SessionSend,
|
||||||
FromAgentName = Utils.StringToBytes(fromName),
|
FromAgentName = Utils.StringToBytes(fromName),
|
||||||
FromGroup = false,
|
FromGroup = false,
|
||||||
Message = Utils.StringToBytes(message),
|
Message = Utils.StringToBytes(messageChunk),
|
||||||
Offline = 0,
|
Offline = 0,
|
||||||
ID = groupID,
|
ID = groupID,
|
||||||
ToAgentID = groupID,
|
ToAgentID = groupID,
|
||||||
|
|
@ -1801,14 +1919,8 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Client.Network.SendPacket(im);
|
Client.Network.SendPacket(im);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Log("No Active group chat session appears to exist, use RequestJoinGroupChat() to join one",
|
|
||||||
Helpers.LogLevel.Error, Client);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3321,14 +3433,36 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
#endregion Teleporting
|
#endregion Teleporting
|
||||||
|
|
||||||
#region Misc
|
#region Profile
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update agent profile
|
/// Update agent profile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="profile"><see cref="OpenMetaverse.Avatar.AvatarProperties"/> struct containing updated
|
/// <param name="profile"><see cref="Avatar.AvatarProperties"/> struct containing updated
|
||||||
/// profile information</param>
|
/// profile information</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// The behavior between LLUDP and Http Capability differs. See each method's remarks
|
||||||
|
/// </remarks>
|
||||||
|
/// <seealso cref="UpdateProfileUdp"/>
|
||||||
|
/// <seealso cref="UpdateProfileHttp"/>
|
||||||
public void UpdateProfile(Avatar.AvatarProperties profile)
|
public void UpdateProfile(Avatar.AvatarProperties profile)
|
||||||
|
{
|
||||||
|
if (Client.Network.CurrentSim.Caps.CapabilityURI(AGENT_PROFILE_CAP) != null)
|
||||||
|
{
|
||||||
|
UpdateProfileHttp(profile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateProfileUdp(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update agent profile via simulator LLUDP
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="profile"><see cref="Avatar.AvatarProperties"/> struct containing updated
|
||||||
|
/// profile information</param>
|
||||||
|
public void UpdateProfileUdp(Avatar.AvatarProperties profile)
|
||||||
{
|
{
|
||||||
AvatarPropertiesUpdatePacket apup = new AvatarPropertiesUpdatePacket
|
AvatarPropertiesUpdatePacket apup = new AvatarPropertiesUpdatePacket
|
||||||
{
|
{
|
||||||
|
|
@ -3352,10 +3486,50 @@ namespace OpenMetaverse
|
||||||
Client.Network.SendPacket(apup);
|
Client.Network.SendPacket(apup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update agent profile
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="profile"><see cref="Avatar.AvatarProperties"/> struct containing updated
|
||||||
|
/// profile information</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <remarks>
|
||||||
|
/// Only updates about text fields, profile url, and allow_publish.
|
||||||
|
/// Does not update image UUID, etc. like the legacy LLUDP request.
|
||||||
|
/// </remarks>
|
||||||
|
public async void UpdateProfileHttp(Avatar.AvatarProperties profile, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var payload = new OSDMap
|
||||||
|
{
|
||||||
|
["sl_about_text"] = profile.AboutText,
|
||||||
|
["fl_about_text"] = profile.FirstLifeText,
|
||||||
|
["profile_url"] = profile.ProfileURL,
|
||||||
|
["allow_publish"] = profile.AllowPublish,
|
||||||
|
["sl_image_id"] = profile.ProfileImage,
|
||||||
|
["fl_image_id"] = profile.FirstLifeImage
|
||||||
|
};
|
||||||
|
|
||||||
|
var capability = Client.Network.CurrentSim.Caps.CapabilityURI(AGENT_PROFILE_CAP);
|
||||||
|
var uri = new Uri($"{capability}/{AgentID}");
|
||||||
|
await Client.HttpCapsClient.PutRequestAsync(uri, OSDFormat.Xml, payload, cancellationToken,
|
||||||
|
(response, data, error) =>
|
||||||
|
{
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
Logger.Log($"AgentProfile update failed: {error.Message}", Helpers.LogLevel.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Logger.Log("AgentProfile update succeeded.", Helpers.LogLevel.Debug);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update agent's profile interests
|
/// Update agent's profile interests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="interests">selection of interests from <see cref="T:OpenMetaverse.Avatar.Interests"/> struct</param>
|
/// <param name="interests">selection of interests from <see cref="Avatar.Interests"/> struct</param>
|
||||||
public void UpdateInterests(Avatar.Interests interests)
|
public void UpdateInterests(Avatar.Interests interests)
|
||||||
{
|
{
|
||||||
AvatarInterestsUpdatePacket aiup = new AvatarInterestsUpdatePacket
|
AvatarInterestsUpdatePacket aiup = new AvatarInterestsUpdatePacket
|
||||||
|
|
@ -3383,7 +3557,21 @@ namespace OpenMetaverse
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">target avatar for notes</param>
|
/// <param name="target">target avatar for notes</param>
|
||||||
/// <param name="notes">notes to store</param>
|
/// <param name="notes">notes to store</param>
|
||||||
|
/// <seealso cref="UpdateProfileHttp"/>
|
||||||
|
/// <seealso cref="UpdateProfileUdp"/>
|
||||||
public void UpdateProfileNotes(UUID target, string notes)
|
public void UpdateProfileNotes(UUID target, string notes)
|
||||||
|
{
|
||||||
|
if (Client.Network.CurrentSim.Caps.CapabilityURI(AGENT_PROFILE_CAP) != null)
|
||||||
|
{
|
||||||
|
UpdateProfileNotesHttp(target, notes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateProfileNotesUdp(target, notes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateProfileNotesUdp(UUID target, string notes)
|
||||||
{
|
{
|
||||||
AvatarNotesUpdatePacket anup = new AvatarNotesUpdatePacket
|
AvatarNotesUpdatePacket anup = new AvatarNotesUpdatePacket
|
||||||
{
|
{
|
||||||
|
|
@ -3402,32 +3590,36 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set the height and the width of the client window. This is used
|
/// Update agent's private notes for target avatar using HTTP capability system
|
||||||
/// by the server to build a virtual camera frustum for our avatar
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="height">New height of the viewer window</param>
|
/// <param name="target">target avatar for notes</param>
|
||||||
/// <param name="width">New width of the viewer window</param>
|
/// <param name="notes">notes to store</param>
|
||||||
public void SetHeightWidth(ushort height, ushort width)
|
/// <param name="cancellationToken"></param>
|
||||||
|
public async void UpdateProfileNotesHttp(UUID target, string notes, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
AgentHeightWidthPacket heightwidth = new AgentHeightWidthPacket
|
var payload = new OSDMap { ["notes"] = notes };
|
||||||
{
|
|
||||||
AgentData =
|
|
||||||
{
|
|
||||||
AgentID = Client.Self.AgentID,
|
|
||||||
SessionID = Client.Self.SessionID,
|
|
||||||
CircuitCode = Client.Network.CircuitCode
|
|
||||||
},
|
|
||||||
HeightWidthBlock =
|
|
||||||
{
|
|
||||||
Height = height,
|
|
||||||
Width = width,
|
|
||||||
GenCounter = heightWidthGenCounter++
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Client.Network.SendPacket(heightwidth);
|
var capability = Client.Network.CurrentSim.Caps.CapabilityURI(AGENT_PROFILE_CAP);
|
||||||
|
var uri = new Uri($"{capability}/{target}");
|
||||||
|
await Client.HttpCapsClient.PutRequestAsync(uri, OSDFormat.Xml, payload, cancellationToken,
|
||||||
|
(response, data, error) =>
|
||||||
|
{
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
Logger.Log($"AgentProfile notes update failed: {error.Message}", Helpers.LogLevel.Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Logger.Log("AgentProfile notes update succeeded.", Helpers.LogLevel.Debug);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Profile
|
||||||
|
|
||||||
|
#region Mute List
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request the list of muted objects and avatars for this agent
|
/// Request the list of muted objects and avatars for this agent
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -3535,10 +3727,41 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Mute List
|
||||||
|
|
||||||
|
#region Misc
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the height and the width of the client window. This is used
|
||||||
|
/// by the server to build a virtual camera frustum for our avatar
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="height">New height of the viewer window</param>
|
||||||
|
/// <param name="width">New width of the viewer window</param>
|
||||||
|
public void SetHeightWidth(ushort height, ushort width)
|
||||||
|
{
|
||||||
|
AgentHeightWidthPacket heightwidth = new AgentHeightWidthPacket
|
||||||
|
{
|
||||||
|
AgentData =
|
||||||
|
{
|
||||||
|
AgentID = Client.Self.AgentID,
|
||||||
|
SessionID = Client.Self.SessionID,
|
||||||
|
CircuitCode = Client.Network.CircuitCode
|
||||||
|
},
|
||||||
|
HeightWidthBlock =
|
||||||
|
{
|
||||||
|
Height = height,
|
||||||
|
Width = width,
|
||||||
|
GenCounter = heightWidthGenCounter++
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Client.Network.SendPacket(heightwidth);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets home location to agents current position
|
/// Sets home location to agents current position
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>will fire an AlertMessage (<see cref="E:OpenMetaverse.AgentManager.OnAlertMessage"/>) with
|
/// <remarks>will fire an AlertMessage (<see cref="OpenMetaverse.AgentManager.OnAlertMessage"/>) with
|
||||||
/// success or failure message</remarks>
|
/// success or failure message</remarks>
|
||||||
public void SetHome()
|
public void SetHome()
|
||||||
{
|
{
|
||||||
|
|
@ -3564,7 +3787,7 @@ namespace OpenMetaverse
|
||||||
/// Move an agent in to a simulator. This packet is the last packet
|
/// Move an agent in to a simulator. This packet is the last packet
|
||||||
/// needed to complete the transition in to a new simulator
|
/// needed to complete the transition in to a new simulator
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="simulator"><see cref="T:OpenMetaverse.Simulator"/> Object</param>
|
/// <param name="simulator"><see cref="OpenMetaverse.Simulator"/> Object</param>
|
||||||
public void CompleteAgentMovement(Simulator simulator)
|
public void CompleteAgentMovement(Simulator simulator)
|
||||||
{
|
{
|
||||||
CompleteAgentMovementPacket move = new CompleteAgentMovementPacket
|
CompleteAgentMovementPacket move = new CompleteAgentMovementPacket
|
||||||
|
|
@ -3584,10 +3807,10 @@ namespace OpenMetaverse
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reply to script permissions request
|
/// Reply to script permissions request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="simulator"><see cref="T:OpenMetaverse.Simulator"/> Object</param>
|
/// <param name="simulator"><see cref="OpenMetaverse.Simulator"/> Object</param>
|
||||||
/// <param name="itemID"><see cref="UUID"/> of the itemID requesting permissions</param>
|
/// <param name="itemID"><see cref="UUID"/> of the itemID requesting permissions</param>
|
||||||
/// <param name="taskID"><see cref="UUID"/> of the taskID requesting permissions</param>
|
/// <param name="taskID"><see cref="UUID"/> of the taskID requesting permissions</param>
|
||||||
/// <param name="permissions"><see cref="OpenMetaverse.ScriptPermission"/> list of permissions to allow</param>
|
/// <param name="permissions"><see cref="ScriptPermission"/> list of permissions to allow</param>
|
||||||
public void ScriptQuestionReply(Simulator simulator, UUID itemID, UUID taskID, ScriptPermission permissions)
|
public void ScriptQuestionReply(Simulator simulator, UUID itemID, UUID taskID, ScriptPermission permissions)
|
||||||
{
|
{
|
||||||
ScriptAnswerYesPacket yes = new ScriptAnswerYesPacket
|
ScriptAnswerYesPacket yes = new ScriptAnswerYesPacket
|
||||||
|
|
|
||||||
|
|
@ -426,6 +426,7 @@ namespace OpenMetaverse
|
||||||
Client.Network.RegisterCallback(PacketType.AgentCachedTextureResponse, AgentCachedTextureResponseHandler);
|
Client.Network.RegisterCallback(PacketType.AgentCachedTextureResponse, AgentCachedTextureResponseHandler);
|
||||||
Client.Network.RegisterCallback(PacketType.RebakeAvatarTextures, RebakeAvatarTexturesHandler);
|
Client.Network.RegisterCallback(PacketType.RebakeAvatarTextures, RebakeAvatarTexturesHandler);
|
||||||
|
|
||||||
|
Client.Objects.ObjectUpdate += Objects_AttachmentUpdate;
|
||||||
Client.Network.Disconnected += Network_OnDisconnected;
|
Client.Network.Disconnected += Network_OnDisconnected;
|
||||||
Client.Network.SimChanged += Network_OnSimChanged;
|
Client.Network.SimChanged += Network_OnSimChanged;
|
||||||
}
|
}
|
||||||
|
|
@ -2716,6 +2717,37 @@ namespace OpenMetaverse
|
||||||
Client.Network.CurrentSim.Caps.CapabilitiesReceived += Simulator_OnCapabilitiesReceived;
|
Client.Network.CurrentSim.Caps.CapabilitiesReceived += Simulator_OnCapabilitiesReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Objects_AttachmentUpdate(object sender, PrimEventArgs e)
|
||||||
|
{
|
||||||
|
Primitive prim = e.Prim;
|
||||||
|
|
||||||
|
if (Client.Self.LocalID == 0
|
||||||
|
|| prim.ParentID != Client.Self.LocalID
|
||||||
|
|| prim.NameValues == null
|
||||||
|
|| !prim.IsAttachment
|
||||||
|
|| !e.IsNew)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates Attachment points as soon as the data arrives
|
||||||
|
for (int i = 0; i < prim.NameValues.Length; ++i)
|
||||||
|
{
|
||||||
|
if (prim.NameValues[i].Name != "AttachItemID")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID inventoryID = new UUID(prim.NameValues[i].Value.ToString());
|
||||||
|
|
||||||
|
if (Attachments.TryGetValue(inventoryID, out AttachmentPoint attachmentPoint))
|
||||||
|
{
|
||||||
|
Attachments.AddOrUpdate(inventoryID, attachmentPoint, (id, value) => prim.PrimData.AttachmentPoint);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Simulator_OnCapabilitiesReceived(object sender, CapabilitiesReceivedEventArgs e)
|
private void Simulator_OnCapabilitiesReceived(object sender, CapabilitiesReceivedEventArgs e)
|
||||||
{
|
{
|
||||||
e.Simulator.Caps.CapabilitiesReceived -= Simulator_OnCapabilitiesReceived;
|
e.Simulator.Caps.CapabilitiesReceived -= Simulator_OnCapabilitiesReceived;
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ namespace OpenMetaverse
|
||||||
/// <returns>String with the file name of the static cached asset</returns>
|
/// <returns>String with the file name of the static cached asset</returns>
|
||||||
private string StaticFileName(UUID assetID)
|
private string StaticFileName(UUID assetID)
|
||||||
{
|
{
|
||||||
return Settings.RESOURCE_DIR + Path.DirectorySeparatorChar + "static_assets" + Path.DirectorySeparatorChar + assetID;
|
return Path.Combine(Settings.RESOURCE_DIR, "static_assets", assetID.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using OpenMetaverse.Http;
|
|
||||||
using OpenMetaverse.Packets;
|
using OpenMetaverse.Packets;
|
||||||
using OpenMetaverse.Interfaces;
|
using OpenMetaverse.Interfaces;
|
||||||
using OpenMetaverse.Messages.Linden;
|
using OpenMetaverse.Messages.Linden;
|
||||||
|
|
@ -169,7 +167,7 @@ namespace OpenMetaverse
|
||||||
public struct ClassifiedAd
|
public struct ClassifiedAd
|
||||||
{
|
{
|
||||||
public UUID ClassifiedID;
|
public UUID ClassifiedID;
|
||||||
public uint Catagory;
|
public uint Category;
|
||||||
public UUID ParcelID;
|
public UUID ParcelID;
|
||||||
public uint ParentEstate;
|
public uint ParentEstate;
|
||||||
public UUID SnapShotID;
|
public UUID SnapShotID;
|
||||||
|
|
@ -681,7 +679,7 @@ namespace OpenMetaverse
|
||||||
Client.Network.SendPacket(request);
|
Client.Network.SendPacket(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get any remaining names after left after the full requests
|
// Get any remaining names left after the full requests
|
||||||
if (ids.Count > n * m)
|
if (ids.Count > n * m)
|
||||||
{
|
{
|
||||||
request = new UUIDNameRequestPacket
|
request = new UUIDNameRequestPacket
|
||||||
|
|
@ -1533,7 +1531,7 @@ namespace OpenMetaverse
|
||||||
Price = p.Data.PriceForListing,
|
Price = p.Data.PriceForListing,
|
||||||
ParentEstate = p.Data.ParentEstate,
|
ParentEstate = p.Data.ParentEstate,
|
||||||
ClassifiedFlags = p.Data.ClassifiedFlags,
|
ClassifiedFlags = p.Data.ClassifiedFlags,
|
||||||
Catagory = p.Data.Category
|
Category = p.Data.Category
|
||||||
};
|
};
|
||||||
|
|
||||||
OnClassifiedInfoReply(new ClassifiedInfoReplyEventArgs(ret.ClassifiedID, ret));
|
OnClassifiedInfoReply(new ClassifiedInfoReplyEventArgs(ret.ClassifiedID, ret));
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022-2024, Sjofn, LLC.
|
* Copyright (c) 2022-2025, Sjofn, LLC.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* - Redistribution and use in source and binary forms, with or without
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
|
|
@ -60,7 +60,7 @@ namespace LibreMetaverse
|
||||||
#region GET requests
|
#region GET requests
|
||||||
|
|
||||||
public async Task GetRequestAsync(Uri uri, CancellationToken cancellationToken,
|
public async Task GetRequestAsync(Uri uri, CancellationToken cancellationToken,
|
||||||
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler)
|
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler = default, ConnectedHandler connectedHandler = default)
|
||||||
{
|
{
|
||||||
using (var request = new HttpRequestMessage(HttpMethod.Get, uri))
|
using (var request = new HttpRequestMessage(HttpMethod.Get, uri))
|
||||||
{
|
{
|
||||||
|
|
@ -68,17 +68,12 @@ namespace LibreMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GetRequestAsync(Uri uri, CancellationToken cancellationToken, DownloadCompleteHandler completeHandler)
|
|
||||||
{
|
|
||||||
await GetRequestAsync(uri, cancellationToken, completeHandler, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion GET requests
|
#endregion GET requests
|
||||||
|
|
||||||
#region POST requests
|
#region POST requests
|
||||||
|
|
||||||
public async Task PostRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
public async Task PostRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
||||||
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler)
|
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler = default, ConnectedHandler connectedHandler = default)
|
||||||
{
|
{
|
||||||
using (var request = new HttpRequestMessage(HttpMethod.Post, uri))
|
using (var request = new HttpRequestMessage(HttpMethod.Post, uri))
|
||||||
{
|
{
|
||||||
|
|
@ -88,14 +83,8 @@ namespace LibreMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PostRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
|
||||||
DownloadCompleteHandler completeHandler)
|
|
||||||
{
|
|
||||||
await PostRequestAsync(uri, contentType, payload, cancellationToken, completeHandler, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task PostRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
public async Task PostRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
||||||
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler)
|
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler = default, ConnectedHandler connectedHandler = default)
|
||||||
{
|
{
|
||||||
SerializeData(format, payload, out var serialized, out var contentType);
|
SerializeData(format, payload, out var serialized, out var contentType);
|
||||||
using (var request = new HttpRequestMessage(HttpMethod.Post, uri))
|
using (var request = new HttpRequestMessage(HttpMethod.Post, uri))
|
||||||
|
|
@ -113,18 +102,12 @@ namespace LibreMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PostRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
|
||||||
DownloadCompleteHandler completeHandler)
|
|
||||||
{
|
|
||||||
await PostRequestAsync(uri, format, payload, cancellationToken, completeHandler, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion POST requests
|
#endregion POST requests
|
||||||
|
|
||||||
#region PUT requests
|
#region PUT requests
|
||||||
|
|
||||||
public async Task PutRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
public async Task PutRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
||||||
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler)
|
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler = default, ConnectedHandler connectedHandler = default)
|
||||||
{
|
{
|
||||||
using (var request = new HttpRequestMessage(HttpMethod.Put, uri))
|
using (var request = new HttpRequestMessage(HttpMethod.Put, uri))
|
||||||
{
|
{
|
||||||
|
|
@ -134,14 +117,8 @@ namespace LibreMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PutRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
|
||||||
DownloadCompleteHandler completeHandler)
|
|
||||||
{
|
|
||||||
await PutRequestAsync(uri, contentType, payload, cancellationToken, completeHandler, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task PutRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
public async Task PutRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
||||||
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler)
|
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler = default, ConnectedHandler connectedHandler = default)
|
||||||
{
|
{
|
||||||
SerializeData(format, payload, out var serialized, out var contentType);
|
SerializeData(format, payload, out var serialized, out var contentType);
|
||||||
using (var request = new HttpRequestMessage(HttpMethod.Put, uri))
|
using (var request = new HttpRequestMessage(HttpMethod.Put, uri))
|
||||||
|
|
@ -152,18 +129,12 @@ namespace LibreMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PutRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
|
||||||
DownloadCompleteHandler completeHandler)
|
|
||||||
{
|
|
||||||
await PutRequestAsync(uri, format, payload, cancellationToken, completeHandler, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion PUT requests
|
#endregion PUT requests
|
||||||
|
|
||||||
#region PATCH requests
|
#region PATCH requests
|
||||||
|
|
||||||
public async Task PatchRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
public async Task PatchRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
||||||
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler)
|
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler = default, ConnectedHandler connectedHandler = default)
|
||||||
{
|
{
|
||||||
#if (NETSTANDARD2_1_OR_GREATER || NET)
|
#if (NETSTANDARD2_1_OR_GREATER || NET)
|
||||||
using (var request = new HttpRequestMessage(HttpMethod.Patch, uri))
|
using (var request = new HttpRequestMessage(HttpMethod.Patch, uri))
|
||||||
|
|
@ -177,14 +148,8 @@ namespace LibreMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PatchRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
|
||||||
DownloadCompleteHandler completeHandler)
|
|
||||||
{
|
|
||||||
await PatchRequestAsync(uri, contentType, payload, cancellationToken, completeHandler, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task PatchRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
public async Task PatchRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
||||||
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler)
|
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler = default, ConnectedHandler connectedHandler = default)
|
||||||
{
|
{
|
||||||
SerializeData(format, payload, out var serialized, out var contentType);
|
SerializeData(format, payload, out var serialized, out var contentType);
|
||||||
#if (NETSTANDARD2_1_OR_GREATER || NET)
|
#if (NETSTANDARD2_1_OR_GREATER || NET)
|
||||||
|
|
@ -199,18 +164,12 @@ namespace LibreMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PatchRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
|
||||||
DownloadCompleteHandler completeHandler)
|
|
||||||
{
|
|
||||||
await PatchRequestAsync(uri, format, payload, cancellationToken, completeHandler, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion PATCH requests
|
#endregion PATCH requests
|
||||||
|
|
||||||
#region DELETE requests
|
#region DELETE requests
|
||||||
|
|
||||||
public async Task DeleteRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
public async Task DeleteRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
||||||
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler)
|
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler = default, ConnectedHandler connectedHandler = default)
|
||||||
{
|
{
|
||||||
using (var request = new HttpRequestMessage(HttpMethod.Delete, uri))
|
using (var request = new HttpRequestMessage(HttpMethod.Delete, uri))
|
||||||
{
|
{
|
||||||
|
|
@ -220,14 +179,8 @@ namespace LibreMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRequestAsync(Uri uri, string contentType, byte[] payload, CancellationToken cancellationToken,
|
|
||||||
DownloadCompleteHandler completeHandler)
|
|
||||||
{
|
|
||||||
await DeleteRequestAsync(uri, contentType, payload, cancellationToken, completeHandler, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
public async Task DeleteRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
||||||
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, ConnectedHandler connectedHandler)
|
DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler = default, ConnectedHandler connectedHandler = default)
|
||||||
{
|
{
|
||||||
SerializeData(format, payload, out var serialized, out var contentType);
|
SerializeData(format, payload, out var serialized, out var contentType);
|
||||||
using (var request = new HttpRequestMessage(HttpMethod.Delete, uri))
|
using (var request = new HttpRequestMessage(HttpMethod.Delete, uri))
|
||||||
|
|
@ -238,12 +191,6 @@ namespace LibreMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRequestAsync(Uri uri, OSDFormat format, OSD payload, CancellationToken cancellationToken,
|
|
||||||
DownloadCompleteHandler completeHandler)
|
|
||||||
{
|
|
||||||
await DeleteRequestAsync(uri, format, payload, cancellationToken, completeHandler, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion DELETE requests
|
#endregion DELETE requests
|
||||||
|
|
||||||
/// /// /// /// /// /// /// /// /// /// /// ///
|
/// /// /// /// /// /// /// /// /// /// /// ///
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2016, openmetaverse.co
|
* Copyright (c) 2006-2016, openmetaverse.co
|
||||||
* Copyright (c) 2019-2024, Sjofn LLC.
|
* Copyright (c) 2019-2025, Sjofn LLC.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* - Redistribution and use in source and binary forms, with or without
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
|
|
@ -36,6 +36,7 @@ using OpenMetaverse.StructuredData;
|
||||||
using OpenMetaverse.Interfaces;
|
using OpenMetaverse.Interfaces;
|
||||||
using OpenMetaverse.Http;
|
using OpenMetaverse.Http;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using LibreMetaverse;
|
||||||
|
|
||||||
namespace OpenMetaverse
|
namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
|
|
@ -319,12 +320,21 @@ namespace OpenMetaverse
|
||||||
_EventQueueClient.Start();
|
_EventQueueClient.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_Caps.TryGetValue("SimulatorFeatures", out var simFeaturesCap))
|
||||||
|
{
|
||||||
|
Logger.DebugLog($"Retrieving Simulator Features", Simulator.Client);
|
||||||
|
Simulator.Features = new SimulatorFeatures(Simulator);
|
||||||
|
_ = Simulator.Client.HttpCapsClient.GetRequestAsync(
|
||||||
|
simFeaturesCap, _HttpCts.Token, Simulator.Features.SetFeatures);
|
||||||
|
}
|
||||||
|
|
||||||
OnCapabilitiesReceived(Simulator);
|
OnCapabilitiesReceived(Simulator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (LitJson.JsonException)
|
catch (LitJson.JsonException)
|
||||||
{
|
{
|
||||||
Logger.Log("Invalid caps response; '" + System.Text.Encoding.UTF8.GetString(responseData) + "' for seed request.", Helpers.LogLevel.Warning, Simulator.Client);
|
Logger.Log($"Invalid caps response; '{System.Text.Encoding.UTF8.GetString(responseData)}' for seed request.",
|
||||||
|
Helpers.LogLevel.Warning, Simulator.Client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2016, openmetaverse.co
|
* Copyright (c) 2006-2016, openmetaverse.co
|
||||||
|
* Copyright (c) 2025, Sjofn LLC.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* - Redistribution and use in source and binary forms, with or without
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
|
|
@ -30,9 +31,10 @@ using OpenMetaverse.Messages.Linden;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using OpenMetaverse.StructuredData;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LibreMetaverse;
|
||||||
|
using OpenMetaverse.StructuredData;
|
||||||
|
|
||||||
namespace OpenMetaverse
|
namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
|
|
@ -350,6 +352,78 @@ namespace OpenMetaverse
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Public Methods
|
#region Public Methods
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates estate-level configuration settings for the current region.
|
||||||
|
/// Attempts to send the update via the "EstateChangeInfo" HTTP caps if available
|
||||||
|
/// or you can enable a fallback to the legacy method.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="estateName">The name of the estate.</param>
|
||||||
|
/// <param name="sunhourvalue">The sun hour value (0.0–24.0, scaled internally).</param>
|
||||||
|
/// <param name="issunfixed">Whether the sun position is fixed.</param>
|
||||||
|
/// <param name="isexternallyvisible">Whether the estate is visible externally.</param>
|
||||||
|
/// <param name="allowdirectteleport">Allow direct teleport to the estate.</param>
|
||||||
|
/// <param name="denyanonymous">Deny access to anonymous users.</param>
|
||||||
|
/// <param name="denyageunverified">Deny access to age-unverified users.</param>
|
||||||
|
/// <param name="blockbots">Block bots from entering the estate.</param>
|
||||||
|
/// <param name="allowvoicechat">Allow voice chat in the estate.</param>
|
||||||
|
/// <param name="overridepublicaccess">Override public access settings.</param>
|
||||||
|
/// <param name="overrideenvironment">Override environment settings.</param>
|
||||||
|
public async Task<Task> UpdateEstateInfo(
|
||||||
|
string estateName, float sunhourvalue, bool issunfixed, bool isexternallyvisible,
|
||||||
|
bool allowdirectteleport, bool denyanonymous, bool denyageunverified, bool blockbots,
|
||||||
|
bool allowvoicechat, bool overridepublicaccess, bool overrideenvironment)
|
||||||
|
{
|
||||||
|
Uri uri = Client.Network.CurrentSim.Caps.CapabilityURI("EstateChangeInfo");
|
||||||
|
if (uri == null)
|
||||||
|
{
|
||||||
|
Logger.Log("using UpdateEstateInfoFallback one day we will have working caps for this", Helpers.LogLevel.Info);
|
||||||
|
List<string> config = new List<string>();
|
||||||
|
config.Add(estateName);
|
||||||
|
Int64 bitmask = 0;
|
||||||
|
if (issunfixed) bitmask |= 1 << 4;
|
||||||
|
if (isexternallyvisible) bitmask |= 1 << 15;
|
||||||
|
if (allowdirectteleport) bitmask |= 1 << 20;
|
||||||
|
if (denyanonymous) bitmask |= 1 << 23;
|
||||||
|
if (denyageunverified) bitmask |= 1 << 30;
|
||||||
|
if (blockbots) bitmask |= 1 << 31;
|
||||||
|
if (allowvoicechat) bitmask |= 1 << 28;
|
||||||
|
if (overridepublicaccess) bitmask |= 1 << 5;
|
||||||
|
if (overrideenvironment) bitmask |= 1 << 9;
|
||||||
|
config.Add(bitmask.ToString(CultureInfo.InvariantCulture));
|
||||||
|
config.Add((sunhourvalue * 1024.0f).ToString(CultureInfo.InvariantCulture));
|
||||||
|
EstateOwnerMessage("estatechangeinfo", config);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
OSDMap body = new OSDMap();
|
||||||
|
body["estate_name"] = estateName;
|
||||||
|
body["sun_hour"] = (sunhourvalue * 1024.0f);
|
||||||
|
body["is_sun_fixed"] = issunfixed;
|
||||||
|
body["is_externally_visible"] = isexternallyvisible;
|
||||||
|
body["allow_direct_teleport"] = allowdirectteleport;
|
||||||
|
body["deny_anonymous"] = denyanonymous;
|
||||||
|
body["deny_age_unverified"] = denyageunverified;
|
||||||
|
body["block_bots"] = blockbots;
|
||||||
|
body["allow_voice_chat"] = allowvoicechat;
|
||||||
|
body["override_public_access"] = overridepublicaccess;
|
||||||
|
body["override_environment"] = overrideenvironment;
|
||||||
|
body["invoice"] = UUID.Random();
|
||||||
|
string requestBody = OSDParser.SerializeLLSDXmlString(body);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = new StringContent(requestBody, Encoding.UTF8, "application/llsd+xml");
|
||||||
|
var reply = await Client.HttpCapsClient.PostAsync(uri.ToString(), content);
|
||||||
|
_ = await reply.Content.ReadAsStringAsync();
|
||||||
|
Logger.Log($"EstateChangeInfo update {reply.StatusCode.ToString()}", Helpers.LogLevel.Info);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Log($"EstateChangeInfo error {e.Message}", Helpers.LogLevel.Error);
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Requests estate information such as top scripts and colliders
|
/// Requests estate information such as top scripts and colliders
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -359,13 +433,21 @@ namespace OpenMetaverse
|
||||||
/// <param name="filter"></param>
|
/// <param name="filter"></param>
|
||||||
public void LandStatRequest(int parcelLocalID, LandStatReportType reportType, uint requestFlags, string filter)
|
public void LandStatRequest(int parcelLocalID, LandStatReportType reportType, uint requestFlags, string filter)
|
||||||
{
|
{
|
||||||
LandStatRequestPacket p = new LandStatRequestPacket();
|
LandStatRequestPacket p = new LandStatRequestPacket
|
||||||
p.AgentData.AgentID = Client.Self.AgentID;
|
{
|
||||||
p.AgentData.SessionID = Client.Self.SessionID;
|
AgentData =
|
||||||
p.RequestData.Filter = Utils.StringToBytes(filter);
|
{
|
||||||
p.RequestData.ParcelLocalID = parcelLocalID;
|
AgentID = Client.Self.AgentID,
|
||||||
p.RequestData.ReportType = (uint)reportType;
|
SessionID = Client.Self.SessionID
|
||||||
p.RequestData.RequestFlags = requestFlags;
|
},
|
||||||
|
RequestData =
|
||||||
|
{
|
||||||
|
Filter = Utils.StringToBytes(filter),
|
||||||
|
ParcelLocalID = parcelLocalID,
|
||||||
|
ReportType = (uint)reportType,
|
||||||
|
RequestFlags = requestFlags
|
||||||
|
}
|
||||||
|
};
|
||||||
Client.Network.SendPacket(p);
|
Client.Network.SendPacket(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -432,11 +514,19 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SimWideDeletesPacket simDelete = new SimWideDeletesPacket();
|
SimWideDeletesPacket simDelete = new SimWideDeletesPacket
|
||||||
simDelete.AgentData.AgentID = Client.Self.AgentID;
|
{
|
||||||
simDelete.AgentData.SessionID = Client.Self.SessionID;
|
AgentData =
|
||||||
simDelete.DataBlock.TargetID = Target;
|
{
|
||||||
simDelete.DataBlock.Flags = (uint)flag;
|
AgentID = Client.Self.AgentID,
|
||||||
|
SessionID = Client.Self.SessionID
|
||||||
|
},
|
||||||
|
DataBlock =
|
||||||
|
{
|
||||||
|
TargetID = Target,
|
||||||
|
Flags = (uint)flag
|
||||||
|
}
|
||||||
|
};
|
||||||
Client.Network.SendPacket(simDelete);
|
Client.Network.SendPacket(simDelete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -458,17 +548,27 @@ namespace OpenMetaverse
|
||||||
/// <param name="listParams">List of parameters to include</param>
|
/// <param name="listParams">List of parameters to include</param>
|
||||||
public void EstateOwnerMessage(string method, List<string> listParams)
|
public void EstateOwnerMessage(string method, List<string> listParams)
|
||||||
{
|
{
|
||||||
EstateOwnerMessagePacket estate = new EstateOwnerMessagePacket();
|
EstateOwnerMessagePacket estate = new EstateOwnerMessagePacket
|
||||||
estate.AgentData.AgentID = Client.Self.AgentID;
|
{
|
||||||
estate.AgentData.SessionID = Client.Self.SessionID;
|
AgentData =
|
||||||
estate.AgentData.TransactionID = UUID.Zero;
|
{
|
||||||
estate.MethodData.Invoice = UUID.Random();
|
AgentID = Client.Self.AgentID,
|
||||||
estate.MethodData.Method = Utils.StringToBytes(method);
|
SessionID = Client.Self.SessionID,
|
||||||
estate.ParamList = new EstateOwnerMessagePacket.ParamListBlock[listParams.Count];
|
TransactionID = UUID.Zero
|
||||||
|
},
|
||||||
|
MethodData =
|
||||||
|
{
|
||||||
|
Invoice = UUID.Random(),
|
||||||
|
Method = Utils.StringToBytes(method)
|
||||||
|
},
|
||||||
|
ParamList = new EstateOwnerMessagePacket.ParamListBlock[listParams.Count]
|
||||||
|
};
|
||||||
for (int i = 0; i < listParams.Count; i++)
|
for (int i = 0; i < listParams.Count; i++)
|
||||||
{
|
{
|
||||||
estate.ParamList[i] = new EstateOwnerMessagePacket.ParamListBlock();
|
estate.ParamList[i] = new EstateOwnerMessagePacket.ParamListBlock
|
||||||
estate.ParamList[i].Parameter = Utils.StringToBytes(listParams[i]);
|
{
|
||||||
|
Parameter = Utils.StringToBytes(listParams[i])
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Client.Network.SendPacket((Packet)estate);
|
Client.Network.SendPacket((Packet)estate);
|
||||||
}
|
}
|
||||||
|
|
@ -570,79 +670,70 @@ namespace OpenMetaverse
|
||||||
EstateOwnerMessage("restart", "-1");
|
EstateOwnerMessage("restart", "-1");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<KeyValuePair<bool, string>> extendedSetRegionInfo(
|
[Obsolete("Use SetRegionInfo with new arguments or SetRegionInfoUdp")]
|
||||||
bool blockTerraform, bool blockFly, bool blockFlyover, bool allowDamage, bool allowLandResell,
|
public void SetRegionInfo(bool blockTerraform, bool blockFly, bool allowDamage, bool allowLandResell,
|
||||||
int agentLimit, float primBonus, RegionMaturity maturityLevel, bool blockObjectPush,
|
bool restrictPushing, bool allowParcelJoinDivide, float agentLimit, float objectBonus,
|
||||||
bool allowParcelChanges, bool blockParcelSearch)
|
RegionMaturity maturity)
|
||||||
{
|
{
|
||||||
if (Client == null)
|
SetRegionInfo(blockTerraform, blockFly, false, allowDamage, allowLandResell, restrictPushing,
|
||||||
{
|
allowParcelJoinDivide, agentLimit, objectBonus, false, maturity);
|
||||||
return new KeyValuePair<bool, string>(false, "No client object");
|
|
||||||
}
|
|
||||||
else if (Client.Network == null)
|
|
||||||
{
|
|
||||||
return new KeyValuePair<bool, string>(false, "Not connected to a network");
|
|
||||||
}
|
|
||||||
else if (Client.Network.CurrentSim == null)
|
|
||||||
{
|
|
||||||
return new KeyValuePair<bool, string>(false, "Not connected to a sim");
|
|
||||||
}
|
|
||||||
else if (Client.Network.CurrentSim.Caps == null)
|
|
||||||
{
|
|
||||||
return new KeyValuePair<bool, string>(false, "No caps endpoint for current sim");
|
|
||||||
}
|
|
||||||
else if (Client.HttpCapsClient == null)
|
|
||||||
{
|
|
||||||
return new KeyValuePair<bool, string>(false, "No HttpCapsClient available");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Uri uri = Client.Network.CurrentSim.Caps.CapabilityURI("DispatchRegionInfo");
|
public void SetRegionInfo(bool blockTerraform, bool blockFly, bool blockFlyOver, bool allowDamage,
|
||||||
if (uri == null)
|
bool allowLandResell, bool restrictPushing, bool allowParcelJoinDivide, float agentLimit, float objectBonus,
|
||||||
|
bool blockParcelSearch, RegionMaturity maturity)
|
||||||
{
|
{
|
||||||
return new KeyValuePair<bool, string>(false, "Unable to get URI for DispatchRegionInfo");
|
if (Client.Network.CurrentSim?.Caps?.CapabilityURI("DispatchRegionInfo") == null
|
||||||
|
|| !SetRegionInfoHttp(blockTerraform, blockFly, blockFlyOver, allowDamage, allowLandResell, restrictPushing,
|
||||||
|
allowParcelJoinDivide, agentLimit, objectBonus, blockParcelSearch, maturity).Result)
|
||||||
|
{
|
||||||
|
Logger.Log("Falling back to LLUDP SetRegionInfo", Helpers.LogLevel.Info);
|
||||||
|
SetRegionInfoUdp(blockTerraform, blockFly, allowDamage, allowLandResell, restrictPushing,
|
||||||
|
allowParcelJoinDivide, agentLimit, objectBonus, maturity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OSDMap request = new OSDMap();
|
|
||||||
request["block_terraform"] = blockTerraform;
|
|
||||||
request["block_fly"] = blockFly;
|
|
||||||
request["block_fly_over"] = blockFlyover;
|
|
||||||
request["allow_damage"] = allowDamage;
|
|
||||||
request["allow_land_resell"] = allowLandResell;
|
|
||||||
request["agent_limit"] = agentLimit;
|
|
||||||
request["prim_bonus"] = primBonus;
|
|
||||||
request["sim_access"] = (int)maturityLevel;
|
|
||||||
request["restrict_pushobject"] = blockObjectPush;
|
|
||||||
request["allow_parcel_changes"] = allowParcelChanges;
|
|
||||||
request["block_parcel_search"] = blockParcelSearch;
|
|
||||||
|
|
||||||
string requestBody = OSDParser.SerializeLLSDXmlString(request);
|
public async Task<bool> SetRegionInfoHttp(bool blockTerraform, bool blockFly, bool blockFlyOver, bool allowDamage,
|
||||||
try
|
bool allowLandResell, bool restrictPushing, bool allowParcelJoinDivide, float agentLimit, float objectBonus,
|
||||||
|
bool blockParcelSearch, RegionMaturity maturity)
|
||||||
|
{
|
||||||
|
var uri = Client.Network.CurrentSim?.Caps?.CapabilityURI("DispatchRegionInfo");
|
||||||
|
if (uri != null)
|
||||||
|
{
|
||||||
|
var req = new OSDMap
|
||||||
|
{
|
||||||
|
["block_terraform"] = blockTerraform,
|
||||||
|
["block_fly"] = blockFly,
|
||||||
|
["block_fly_over"] = blockFlyOver,
|
||||||
|
["allow_damage"] = allowDamage,
|
||||||
|
["allow_land_resell"] = allowLandResell,
|
||||||
|
["agent_limit"] = agentLimit,
|
||||||
|
["prim_bonus"] = objectBonus,
|
||||||
|
["sim_access"] = maturity.ToString("D"),
|
||||||
|
["restrict_pushobject"] = restrictPushing,
|
||||||
|
["allow_parcel_changes"] = allowParcelJoinDivide,
|
||||||
|
["block_parcel_search"] = blockParcelSearch
|
||||||
|
};
|
||||||
|
using (var content = new StringContent(OSDParser.SerializeLLSDXmlString(req), Encoding.UTF8,
|
||||||
|
"application/llsd+xml"))
|
||||||
|
{
|
||||||
|
using (var reply = await Client.HttpCapsClient.PostAsync(uri, content))
|
||||||
{
|
{
|
||||||
var content = new StringContent(requestBody, Encoding.UTF8, "application/llsd+xml");
|
|
||||||
var reply = await Client.HttpCapsClient.PostAsync(uri.ToString(), content);
|
|
||||||
string responseContent = await reply.Content.ReadAsStringAsync();
|
|
||||||
|
|
||||||
if (reply.IsSuccessStatusCode)
|
if (reply.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return new KeyValuePair<bool, string>(true, "ok");
|
return true;
|
||||||
}
|
}
|
||||||
return new KeyValuePair<bool, string>(false, $"HTTP {reply.StatusCode}: {responseContent}");
|
|
||||||
|
Logger.Log($"Failed to set region info via capability: {reply.ReasonPhrase}", Helpers.LogLevel.Warning);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return new KeyValuePair<bool, string>(false, e.Message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Estate panel "Region" tab settings</summary>
|
/// <summary>Estate panel "Region" tab settings</summary>
|
||||||
/// @deprecated Use the version with RegionMaturity support
|
public void SetRegionInfoUdp(bool blockTerraform, bool blockFly, bool allowDamage, bool allowLandResell,
|
||||||
public void SetRegionInfo(bool blockTerraform, bool blockFly, bool allowDamage, bool allowLandResell, bool restrictPushing, bool allowParcelJoinDivide, float agentLimit, float objectBonus, bool mature)
|
bool restrictPushing, bool allowParcelJoinDivide, float agentLimit, float objectBonus, RegionMaturity maturity)
|
||||||
{
|
|
||||||
RegionMaturity rating = mature ? RegionMaturity.Mature : RegionMaturity.PG;
|
|
||||||
SetRegionInfo(blockTerraform, blockFly, allowDamage, allowLandResell, restrictPushing, allowParcelJoinDivide, agentLimit, objectBonus, rating);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Estate panel "Region" tab settings</summary>
|
|
||||||
public void SetRegionInfo(bool blockTerraform, bool blockFly, bool allowDamage, bool allowLandResell, bool restrictPushing, bool allowParcelJoinDivide, float agentLimit, float objectBonus, RegionMaturity maturity)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
List<string> listParams = new List<string>();
|
List<string> listParams = new List<string>();
|
||||||
|
|
@ -652,7 +743,7 @@ namespace OpenMetaverse
|
||||||
listParams.Add(allowLandResell ? "Y" : "N");
|
listParams.Add(allowLandResell ? "Y" : "N");
|
||||||
listParams.Add(agentLimit.ToString(CultureInfo.InvariantCulture));
|
listParams.Add(agentLimit.ToString(CultureInfo.InvariantCulture));
|
||||||
listParams.Add(objectBonus.ToString(CultureInfo.InvariantCulture));
|
listParams.Add(objectBonus.ToString(CultureInfo.InvariantCulture));
|
||||||
listParams.Add(maturity.ToString());
|
listParams.Add(maturity.ToString("D"));
|
||||||
listParams.Add(restrictPushing ? "Y" : "N");
|
listParams.Add(restrictPushing ? "Y" : "N");
|
||||||
listParams.Add(allowParcelJoinDivide ? "Y" : "N");
|
listParams.Add(allowParcelJoinDivide ? "Y" : "N");
|
||||||
EstateOwnerMessage("setregioninfo", listParams);
|
EstateOwnerMessage("setregioninfo", listParams);
|
||||||
|
|
@ -699,12 +790,51 @@ namespace OpenMetaverse
|
||||||
/// <summary>Requests the estate covenant</summary>
|
/// <summary>Requests the estate covenant</summary>
|
||||||
public void RequestCovenant()
|
public void RequestCovenant()
|
||||||
{
|
{
|
||||||
EstateCovenantRequestPacket req = new EstateCovenantRequestPacket();
|
EstateCovenantRequestPacket req = new EstateCovenantRequestPacket
|
||||||
req.AgentData.AgentID = Client.Self.AgentID;
|
{
|
||||||
req.AgentData.SessionID = Client.Self.SessionID;
|
AgentData =
|
||||||
|
{
|
||||||
|
AgentID = Client.Self.AgentID,
|
||||||
|
SessionID = Client.Self.SessionID
|
||||||
|
}
|
||||||
|
};
|
||||||
Client.Network.SendPacket(req);
|
Client.Network.SendPacket(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests Estate Covenant notecard from <see cref="Client.Network.CurrentSim" /> asset service
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="covenantId">Asset UUID for estate covenant notecard</param>
|
||||||
|
/// <param name="callback">Asset Received callback</param>
|
||||||
|
/// <seealso cref="AssetManager.RequestAssetUDP"/>
|
||||||
|
public void RequestCovenantNotecard(UUID covenantId, AssetManager.AssetReceivedCallback callback)
|
||||||
|
{
|
||||||
|
RequestCovenantNotecard(covenantId, Client.Network.CurrentSim, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests Estate Covenant notecard from asset service
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="covenantId">Asset UUID for estate covenant notecard</param>
|
||||||
|
/// <param name="simulator">Requested simulator</param>
|
||||||
|
/// <param name="callback">Asset Received callback</param>
|
||||||
|
/// <seealso cref="AssetManager.RequestAssetUDP"/>
|
||||||
|
public void RequestCovenantNotecard(UUID covenantId, Simulator simulator, AssetManager.AssetReceivedCallback callback)
|
||||||
|
{
|
||||||
|
var transfer = new AssetDownload
|
||||||
|
{
|
||||||
|
ID = UUID.Random(),
|
||||||
|
AssetID = covenantId,
|
||||||
|
AssetType = AssetType.Notecard,
|
||||||
|
Priority = 101.0f,
|
||||||
|
Channel = ChannelType.Asset,
|
||||||
|
Source = SourceType.SimEstate,
|
||||||
|
Simulator = simulator,
|
||||||
|
Callback = callback
|
||||||
|
};
|
||||||
|
Client.Assets.RequestEstateAsset(transfer, EstateAssetType.Covenant);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Upload a terrain RAW file
|
/// Upload a terrain RAW file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -713,11 +843,13 @@ namespace OpenMetaverse
|
||||||
/// <returns>The Id of the transfer request</returns>
|
/// <returns>The Id of the transfer request</returns>
|
||||||
public UUID UploadTerrain(byte[] fileData, string fileName)
|
public UUID UploadTerrain(byte[] fileData, string fileName)
|
||||||
{
|
{
|
||||||
AssetUpload upload = new AssetUpload();
|
AssetUpload upload = new AssetUpload
|
||||||
upload.AssetData = fileData;
|
{
|
||||||
upload.AssetType = AssetType.Unknown;
|
AssetData = fileData,
|
||||||
upload.Size = fileData.Length;
|
AssetType = AssetType.Unknown,
|
||||||
upload.ID = UUID.Random();
|
Size = fileData.Length,
|
||||||
|
ID = UUID.Random()
|
||||||
|
};
|
||||||
|
|
||||||
// Tell the library we have a pending file to upload
|
// Tell the library we have a pending file to upload
|
||||||
Client.Assets.SetPendingAssetUploadData(upload);
|
Client.Assets.SetPendingAssetUploadData(upload);
|
||||||
|
|
@ -987,13 +1119,15 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
foreach (LandStatReplyPacket.ReportDataBlock rep in p.ReportData)
|
foreach (LandStatReplyPacket.ReportDataBlock rep in p.ReportData)
|
||||||
{
|
{
|
||||||
EstateTask task = new EstateTask();
|
EstateTask task = new EstateTask
|
||||||
task.Position = new Vector3(rep.LocationX, rep.LocationY, rep.LocationZ);
|
{
|
||||||
task.Score = rep.Score;
|
Position = new Vector3(rep.LocationX, rep.LocationY, rep.LocationZ),
|
||||||
task.TaskID = rep.TaskID;
|
Score = rep.Score,
|
||||||
task.TaskLocalID = rep.TaskLocalID;
|
TaskID = rep.TaskID,
|
||||||
task.TaskName = Utils.BytesToString(rep.TaskName);
|
TaskLocalID = rep.TaskLocalID,
|
||||||
task.OwnerName = Utils.BytesToString(rep.OwnerName);
|
TaskName = Utils.BytesToString(rep.TaskName),
|
||||||
|
OwnerName = Utils.BytesToString(rep.OwnerName)
|
||||||
|
};
|
||||||
Tasks.Add(task.TaskID, task);
|
Tasks.Add(task.TaskID, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1030,14 +1164,16 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
foreach (LandStatReplyMessage.ReportDataBlock rep in m.ReportDataBlocks)
|
foreach (LandStatReplyMessage.ReportDataBlock rep in m.ReportDataBlocks)
|
||||||
{
|
{
|
||||||
EstateTask task = new EstateTask();
|
EstateTask task = new EstateTask
|
||||||
task.Position = rep.Location;
|
{
|
||||||
task.Score = rep.Score;
|
Position = rep.Location,
|
||||||
task.MonoScore = rep.MonoScore;
|
Score = rep.Score,
|
||||||
task.TaskID = rep.TaskID;
|
MonoScore = rep.MonoScore,
|
||||||
task.TaskLocalID = rep.TaskLocalID;
|
TaskID = rep.TaskID,
|
||||||
task.TaskName = rep.TaskName;
|
TaskLocalID = rep.TaskLocalID,
|
||||||
task.OwnerName = rep.OwnerName;
|
TaskName = rep.TaskName,
|
||||||
|
OwnerName = rep.OwnerName
|
||||||
|
};
|
||||||
Tasks.Add(task.TaskID, task);
|
Tasks.Add(task.TaskID, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2016, openmetaverse.co
|
* Copyright (c) 2006-2016, openmetaverse.co
|
||||||
* Copyright (c) 2022, Sjofn, LLC.
|
* Copyright (c) 2022-2025, Sjofn, LLC.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* - Redistribution and use in source and binary forms, with or without
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
|
|
@ -27,7 +27,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using OpenMetaverse.StructuredData;
|
using OpenMetaverse.StructuredData;
|
||||||
|
|
@ -160,16 +159,15 @@ namespace OpenMetaverse
|
||||||
public uint GlobalY;
|
public uint GlobalY;
|
||||||
|
|
||||||
/// <summary>Get the Local X position of the item</summary>
|
/// <summary>Get the Local X position of the item</summary>
|
||||||
public uint LocalX { get { return GlobalX % Simulator.DefaultRegionSizeX; } }
|
public uint LocalX => GlobalX % Simulator.DefaultRegionSizeX;
|
||||||
|
|
||||||
/// <summary>Get the Local Y position of the item</summary>
|
/// <summary>Get the Local Y position of the item</summary>
|
||||||
public uint LocalY { get { return GlobalY % Simulator.DefaultRegionSizeY; } }
|
public uint LocalY => GlobalY % Simulator.DefaultRegionSizeY;
|
||||||
|
|
||||||
/// <summary>Get the Handle of the region</summary>
|
/// <summary>Get the Handle of the region</summary>
|
||||||
public ulong RegionHandle
|
public ulong RegionHandle =>
|
||||||
{
|
Utils.UIntsToLong((uint)(GlobalX - (GlobalX % Simulator.DefaultRegionSizeX)),
|
||||||
get { return Utils.UIntsToLong((uint)(GlobalX - (GlobalX % Simulator.DefaultRegionSizeX)),
|
(uint)(GlobalY - (GlobalY % Simulator.DefaultRegionSizeY)));
|
||||||
(uint)(GlobalY - (GlobalY % Simulator.DefaultRegionSizeY))); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -578,7 +576,7 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves <see cref="GridRegion"/> information using the region name
|
/// Retrieves <see cref="GridRegion"/> information using the region handle
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>This function will block until it can find the region or gives up</remarks>
|
/// <remarks>This function will block until it can find the region or gives up</remarks>
|
||||||
/// <param name="handle">Region Handle of requested <see cref="GridRegion"/></param>
|
/// <param name="handle">Region Handle of requested <see cref="GridRegion"/></param>
|
||||||
|
|
@ -595,10 +593,7 @@ namespace OpenMetaverse
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint globalX,
|
Utils.LongToUInts(handle, out var globalX, out var globalY);
|
||||||
globalY;
|
|
||||||
|
|
||||||
Utils.LongToUInts(handle, out globalX, out globalY);
|
|
||||||
const uint regionWidthUnits = 256;
|
const uint regionWidthUnits = 256;
|
||||||
ushort gridX = (ushort)(globalX / regionWidthUnits);
|
ushort gridX = (ushort)(globalX / regionWidthUnits);
|
||||||
ushort gridY = (ushort)(globalY / regionWidthUnits);
|
ushort gridY = (ushort)(globalY / regionWidthUnits);
|
||||||
|
|
@ -663,7 +658,7 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
void Callback(object sender, GridRegionEventArgs e)
|
void Callback(object sender, GridRegionEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Region.Name.ToLowerInvariant() == name.ToLowerInvariant())
|
if (string.Equals(e.Region.Name, name, StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
regionEvent.Set();
|
regionEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2016, openmetaverse.co
|
* Copyright (c) 2006-2016, openmetaverse.co
|
||||||
|
* Copyright (c) 2025, Sjofn, LLC
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* - Redistribution and use in source and binary forms, with or without
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
|
|
@ -33,7 +34,6 @@ using OpenMetaverse.Packets;
|
||||||
using OpenMetaverse.StructuredData;
|
using OpenMetaverse.StructuredData;
|
||||||
using OpenMetaverse.Messages.Linden;
|
using OpenMetaverse.Messages.Linden;
|
||||||
using OpenMetaverse.Interfaces;
|
using OpenMetaverse.Interfaces;
|
||||||
using OpenMetaverse.Http;
|
|
||||||
|
|
||||||
namespace OpenMetaverse
|
namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
|
|
@ -253,13 +253,13 @@ namespace OpenMetaverse
|
||||||
if (OwnerID == UUID.Zero || AttachmentID == UUID.Zero)
|
if (OwnerID == UUID.Zero || AttachmentID == UUID.Zero)
|
||||||
return Utils.EmptyBytes;
|
return Utils.EmptyBytes;
|
||||||
|
|
||||||
OpenMetaverse.StructuredData.OSDMap att = new OpenMetaverse.StructuredData.OSDMap
|
OSDMap att = new OSDMap
|
||||||
{
|
{
|
||||||
{"item_id", OpenMetaverse.StructuredData.OSD.FromUUID(AttachmentID)},
|
{"item_id", OSD.FromUUID(AttachmentID)},
|
||||||
{"owner_id", OpenMetaverse.StructuredData.OSD.FromUUID(OwnerID)}
|
{"owner_id", OSD.FromUUID(OwnerID)}
|
||||||
};
|
};
|
||||||
|
|
||||||
return OpenMetaverse.StructuredData.OSDParser.SerializeLLSDXmlBytes(att);
|
return OSDParser.SerializeLLSDXmlBytes(att);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
//I guess this is how this works, no gaurentees
|
//I guess this is how this works, no gaurentees
|
||||||
|
|
@ -845,7 +845,7 @@ namespace OpenMetaverse
|
||||||
/// <summary>Thread sync lock object</summary>
|
/// <summary>Thread sync lock object</summary>
|
||||||
private readonly object m_BannedAgentsLock = new object();
|
private readonly object m_BannedAgentsLock = new object();
|
||||||
|
|
||||||
/// <summary>Raised when another agent invites our avatar to join a group</summary>
|
/// <summary>Raised when a group ban is processed</summary>
|
||||||
public event EventHandler<BannedAgentsEventArgs> BannedAgents
|
public event EventHandler<BannedAgentsEventArgs> BannedAgents
|
||||||
{
|
{
|
||||||
add { lock (m_BannedAgentsLock) { m_BannedAgents += value; } }
|
add { lock (m_BannedAgentsLock) { m_BannedAgents += value; } }
|
||||||
|
|
@ -854,21 +854,20 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
#endregion Delegates
|
#endregion Delegates
|
||||||
|
|
||||||
|
|
||||||
/// <summary>A reference to the current <see cref="GridClient"/> instance</summary>
|
/// <summary>A reference to the current <see cref="GridClient"/> instance</summary>
|
||||||
private GridClient Client;
|
private readonly GridClient Client;
|
||||||
/// <summary>Currently-active group members requests</summary>
|
/// <summary>Currently-active group members requests</summary>
|
||||||
private List<UUID> GroupMembersRequests;
|
private readonly List<UUID> GroupMembersRequests;
|
||||||
/// <summary>Currently-active group roles requests</summary>
|
/// <summary>Currently-active group roles requests</summary>
|
||||||
private List<UUID> GroupRolesRequests;
|
private readonly List<UUID> GroupRolesRequests;
|
||||||
/// <summary>Currently-active group role-member requests</summary>
|
/// <summary>Currently-active group role-member requests</summary>
|
||||||
private List<UUID> GroupRolesMembersRequests;
|
private readonly List<UUID> GroupRolesMembersRequests;
|
||||||
/// <summary>Dictionary keeping group members while request is in progress</summary>
|
/// <summary>Dictionary keeping group members while request is in progress</summary>
|
||||||
private LockingDictionary<UUID, Dictionary<UUID, GroupMember>> TempGroupMembers;
|
private readonly LockingDictionary<UUID, Dictionary<UUID, GroupMember>> TempGroupMembers;
|
||||||
/// <summary>Dictionary keeping mebmer/role mapping while request is in progress</summary>
|
/// <summary>Dictionary keeping member/role mapping while request is in progress</summary>
|
||||||
private LockingDictionary<UUID, List<KeyValuePair<UUID, UUID>>> TempGroupRolesMembers;
|
private readonly LockingDictionary<UUID, List<KeyValuePair<UUID, UUID>>> TempGroupRolesMembers;
|
||||||
/// <summary>Dictionary keeping GroupRole information while request is in progress</summary>
|
/// <summary>Dictionary keeping GroupRole information while request is in progress</summary>
|
||||||
private LockingDictionary<UUID, Dictionary<UUID, GroupRole>> TempGroupRoles;
|
private readonly LockingDictionary<UUID, Dictionary<UUID, GroupRole>> TempGroupRoles;
|
||||||
/// <summary>Caches group name lookups</summary>
|
/// <summary>Caches group name lookups</summary>
|
||||||
public LockingDictionary<UUID, string> GroupName2KeyCache;
|
public LockingDictionary<UUID, string> GroupName2KeyCache;
|
||||||
|
|
||||||
|
|
@ -890,7 +889,7 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
Client.Self.IM += Self_IM;
|
Client.Self.IM += Self_IM;
|
||||||
|
|
||||||
Client.Network.RegisterEventCallback("AgentGroupDataUpdate", new Caps.EventQueueCallback(AgentGroupDataUpdateMessageHandler));
|
Client.Network.RegisterEventCallback("AgentGroupDataUpdate", AgentGroupDataUpdateMessageHandler);
|
||||||
// deprecated in simulator v1.27
|
// deprecated in simulator v1.27
|
||||||
Client.Network.RegisterCallback(PacketType.AgentDropGroup, AgentDropGroupHandler);
|
Client.Network.RegisterCallback(PacketType.AgentDropGroup, AgentDropGroupHandler);
|
||||||
Client.Network.RegisterCallback(PacketType.GroupTitlesReply, GroupTitlesReplyHandler);
|
Client.Network.RegisterCallback(PacketType.GroupTitlesReply, GroupTitlesReplyHandler);
|
||||||
|
|
@ -908,10 +907,10 @@ namespace OpenMetaverse
|
||||||
Client.Network.RegisterCallback(PacketType.EjectGroupMemberReply, EjectGroupMemberReplyHandler);
|
Client.Network.RegisterCallback(PacketType.EjectGroupMemberReply, EjectGroupMemberReplyHandler);
|
||||||
Client.Network.RegisterCallback(PacketType.GroupNoticesListReply, GroupNoticesListReplyHandler);
|
Client.Network.RegisterCallback(PacketType.GroupNoticesListReply, GroupNoticesListReplyHandler);
|
||||||
|
|
||||||
Client.Network.RegisterEventCallback("AgentDropGroup", new Caps.EventQueueCallback(AgentDropGroupMessageHandler));
|
Client.Network.RegisterEventCallback("AgentDropGroup", AgentDropGroupMessageHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Self_IM(object sender, InstantMessageEventArgs e)
|
private void Self_IM(object sender, InstantMessageEventArgs e)
|
||||||
{
|
{
|
||||||
if (m_GroupInvitation == null || e.IM.Dialog != InstantMessageDialog.GroupInvitation) return;
|
if (m_GroupInvitation == null || e.IM.Dialog != InstantMessageDialog.GroupInvitation) return;
|
||||||
|
|
||||||
|
|
@ -930,7 +929,6 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region Public Methods
|
#region Public Methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1044,9 +1042,10 @@ namespace OpenMetaverse
|
||||||
public UUID RequestGroupMembers(UUID group)
|
public UUID RequestGroupMembers(UUID group)
|
||||||
{
|
{
|
||||||
UUID requestID = UUID.Random();
|
UUID requestID = UUID.Random();
|
||||||
Uri cap = null;
|
Uri cap = Client.Network.CurrentSim?.Caps?.CapabilityURI("GroupMemberData");
|
||||||
|
|
||||||
if ((cap = Client.Network.CurrentSim?.Caps?.CapabilityURI("GroupMemberData")) != null)
|
// Request from Capability
|
||||||
|
if (cap != null)
|
||||||
{
|
{
|
||||||
OSDMap payload = new OSDMap(1) { ["group_id"] = @group };
|
OSDMap payload = new OSDMap(1) { ["group_id"] = @group };
|
||||||
Task req = Client.HttpCapsClient.PostRequestAsync(cap, OSDFormat.Xml, payload, CancellationToken.None,
|
Task req = Client.HttpCapsClient.PostRequestAsync(cap, OSDFormat.Xml, payload, CancellationToken.None,
|
||||||
|
|
@ -1058,7 +1057,7 @@ namespace OpenMetaverse
|
||||||
GroupMembersHandlerCaps(requestID, result);
|
GroupMembersHandlerCaps(requestID, result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else // fallback to LLUDP
|
||||||
{
|
{
|
||||||
lock (GroupMembersRequests) GroupMembersRequests.Add(requestID);
|
lock (GroupMembersRequests) GroupMembersRequests.Add(requestID);
|
||||||
|
|
||||||
|
|
@ -1190,9 +1189,9 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
/// <summary>Invites a user to a group</summary>
|
/// <summary>Invites a user to a group</summary>
|
||||||
/// <param name="group">The group to invite to</param>
|
/// <param name="group">The group to invite to</param>
|
||||||
/// <param name="roles">A list of roles to invite a person to</param>
|
/// <param name="roles">A list of roles to invite an agent to</param>
|
||||||
/// <param name="personkey">Key of person to invite</param>
|
/// <param name="requestedAgent">Key of agent to invite</param>
|
||||||
public void Invite(UUID group, List<UUID> roles, UUID personkey)
|
public void Invite(UUID group, List<UUID> roles, UUID requestedAgent)
|
||||||
{
|
{
|
||||||
InviteGroupRequestPacket igp = new InviteGroupRequestPacket
|
InviteGroupRequestPacket igp = new InviteGroupRequestPacket
|
||||||
{
|
{
|
||||||
|
|
@ -1208,7 +1207,7 @@ namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
igp.InviteData[i] = new InviteGroupRequestPacket.InviteDataBlock
|
igp.InviteData[i] = new InviteGroupRequestPacket.InviteDataBlock
|
||||||
{
|
{
|
||||||
InviteeID = personkey,
|
InviteeID = requestedAgent,
|
||||||
RoleID = roles[i]
|
RoleID = roles[i]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -1276,7 +1275,7 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Save wheather agent wants to accept group notices and list this group in their profile
|
/// Set agent's group preferences
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="groupID">Group <see cref="UUID"/></param>
|
/// <param name="groupID">Group <see cref="UUID"/></param>
|
||||||
/// <param name="acceptNotices">Accept notices from this group</param>
|
/// <param name="acceptNotices">Accept notices from this group</param>
|
||||||
|
|
@ -1307,11 +1306,18 @@ namespace OpenMetaverse
|
||||||
/// <param name="id">group ID (UUID) to join.</param>
|
/// <param name="id">group ID (UUID) to join.</param>
|
||||||
public void RequestJoinGroup(UUID id)
|
public void RequestJoinGroup(UUID id)
|
||||||
{
|
{
|
||||||
JoinGroupRequestPacket join = new JoinGroupRequestPacket();
|
JoinGroupRequestPacket join = new JoinGroupRequestPacket
|
||||||
join.AgentData.AgentID = Client.Self.AgentID;
|
{
|
||||||
join.AgentData.SessionID = Client.Self.SessionID;
|
AgentData =
|
||||||
|
{
|
||||||
join.GroupData.GroupID = id;
|
AgentID = Client.Self.AgentID,
|
||||||
|
SessionID = Client.Self.SessionID
|
||||||
|
},
|
||||||
|
GroupData =
|
||||||
|
{
|
||||||
|
GroupID = id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Client.Network.SendPacket(join);
|
Client.Network.SendPacket(join);
|
||||||
}
|
}
|
||||||
|
|
@ -1324,7 +1330,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="group">Group struct containing the new group info</param>
|
/// <param name="group">Group struct containing the new group info</param>
|
||||||
public void RequestCreateGroup(Group group)
|
public void RequestCreateGroup(Group group)
|
||||||
{
|
{
|
||||||
OpenMetaverse.Packets.CreateGroupRequestPacket cgrp = new CreateGroupRequestPacket
|
CreateGroupRequestPacket cgrp = new CreateGroupRequestPacket
|
||||||
{
|
{
|
||||||
AgentData = new CreateGroupRequestPacket.AgentDataBlock
|
AgentData = new CreateGroupRequestPacket.AgentDataBlock
|
||||||
{
|
{
|
||||||
|
|
@ -1352,24 +1358,24 @@ namespace OpenMetaverse
|
||||||
/// <param name="group">Group struct to update.</param>
|
/// <param name="group">Group struct to update.</param>
|
||||||
public void UpdateGroup(UUID id, Group group)
|
public void UpdateGroup(UUID id, Group group)
|
||||||
{
|
{
|
||||||
OpenMetaverse.Packets.UpdateGroupInfoPacket cgrp = new UpdateGroupInfoPacket
|
UpdateGroupInfoPacket cgrp = new UpdateGroupInfoPacket
|
||||||
{
|
{
|
||||||
AgentData = new UpdateGroupInfoPacket.AgentDataBlock
|
AgentData = new UpdateGroupInfoPacket.AgentDataBlock
|
||||||
{
|
{
|
||||||
AgentID = Client.Self.AgentID,
|
AgentID = Client.Self.AgentID,
|
||||||
SessionID = Client.Self.SessionID
|
SessionID = Client.Self.SessionID
|
||||||
}
|
},
|
||||||
};
|
GroupData = new UpdateGroupInfoPacket.GroupDataBlock
|
||||||
cgrp.GroupData = new UpdateGroupInfoPacket.GroupDataBlock
|
|
||||||
{
|
{
|
||||||
GroupID = id,
|
GroupID = id,
|
||||||
AllowPublish = @group.AllowPublish,
|
AllowPublish = group.AllowPublish,
|
||||||
Charter = Utils.StringToBytes(@group.Charter),
|
Charter = Utils.StringToBytes(group.Charter),
|
||||||
InsigniaID = @group.InsigniaID,
|
InsigniaID = group.InsigniaID,
|
||||||
MaturePublish = @group.MaturePublish,
|
MaturePublish = group.MaturePublish,
|
||||||
MembershipFee = @group.MembershipFee,
|
MembershipFee = group.MembershipFee,
|
||||||
OpenEnrollment = @group.OpenEnrollment,
|
OpenEnrollment = group.OpenEnrollment,
|
||||||
ShowInList = @group.ShowInList
|
ShowInList = group.ShowInList
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Client.Network.SendPacket(cgrp);
|
Client.Network.SendPacket(cgrp);
|
||||||
|
|
@ -1380,16 +1386,16 @@ namespace OpenMetaverse
|
||||||
/// <param name="member">Avatar's key to eject</param>
|
/// <param name="member">Avatar's key to eject</param>
|
||||||
public void EjectUser(UUID group, UUID member)
|
public void EjectUser(UUID group, UUID member)
|
||||||
{
|
{
|
||||||
OpenMetaverse.Packets.EjectGroupMemberRequestPacket eject = new EjectGroupMemberRequestPacket
|
EjectGroupMemberRequestPacket eject = new EjectGroupMemberRequestPacket
|
||||||
{
|
{
|
||||||
AgentData = new EjectGroupMemberRequestPacket.AgentDataBlock
|
AgentData = new EjectGroupMemberRequestPacket.AgentDataBlock
|
||||||
{
|
{
|
||||||
AgentID = Client.Self.AgentID,
|
AgentID = Client.Self.AgentID,
|
||||||
SessionID = Client.Self.SessionID
|
SessionID = Client.Self.SessionID
|
||||||
}
|
},
|
||||||
|
GroupData = new EjectGroupMemberRequestPacket.GroupDataBlock {GroupID = group},
|
||||||
|
EjectData = new EjectGroupMemberRequestPacket.EjectDataBlock[1]
|
||||||
};
|
};
|
||||||
eject.GroupData = new EjectGroupMemberRequestPacket.GroupDataBlock {GroupID = @group};
|
|
||||||
eject.EjectData = new EjectGroupMemberRequestPacket.EjectDataBlock[1];
|
|
||||||
eject.EjectData[0] = new EjectGroupMemberRequestPacket.EjectDataBlock {EjecteeID = member};
|
eject.EjectData[0] = new EjectGroupMemberRequestPacket.EjectDataBlock {EjecteeID = member};
|
||||||
|
|
||||||
Client.Network.SendPacket(eject);
|
Client.Network.SendPacket(eject);
|
||||||
|
|
@ -1399,7 +1405,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="role">Modified role to be updated</param>
|
/// <param name="role">Modified role to be updated</param>
|
||||||
public void UpdateRole(GroupRole role)
|
public void UpdateRole(GroupRole role)
|
||||||
{
|
{
|
||||||
OpenMetaverse.Packets.GroupRoleUpdatePacket gru =
|
GroupRoleUpdatePacket gru =
|
||||||
new GroupRoleUpdatePacket
|
new GroupRoleUpdatePacket
|
||||||
{
|
{
|
||||||
AgentData =
|
AgentData =
|
||||||
|
|
@ -1427,7 +1433,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="role">Role to create</param>
|
/// <param name="role">Role to create</param>
|
||||||
public void CreateRole(UUID group, GroupRole role)
|
public void CreateRole(UUID group, GroupRole role)
|
||||||
{
|
{
|
||||||
OpenMetaverse.Packets.GroupRoleUpdatePacket gru =
|
GroupRoleUpdatePacket gru =
|
||||||
new GroupRoleUpdatePacket
|
new GroupRoleUpdatePacket
|
||||||
{
|
{
|
||||||
AgentData =
|
AgentData =
|
||||||
|
|
@ -1455,7 +1461,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="roleID">Role to delete</param>
|
/// <param name="roleID">Role to delete</param>
|
||||||
public void DeleteRole(UUID group, UUID roleID)
|
public void DeleteRole(UUID group, UUID roleID)
|
||||||
{
|
{
|
||||||
OpenMetaverse.Packets.GroupRoleUpdatePacket gru =
|
GroupRoleUpdatePacket gru =
|
||||||
new GroupRoleUpdatePacket
|
new GroupRoleUpdatePacket
|
||||||
{
|
{
|
||||||
AgentData =
|
AgentData =
|
||||||
|
|
@ -1484,7 +1490,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="member">Avatar's Key to remove</param>
|
/// <param name="member">Avatar's Key to remove</param>
|
||||||
public void RemoveFromRole(UUID group, UUID role, UUID member)
|
public void RemoveFromRole(UUID group, UUID role, UUID member)
|
||||||
{
|
{
|
||||||
OpenMetaverse.Packets.GroupRoleChangesPacket grc =
|
GroupRoleChangesPacket grc =
|
||||||
new GroupRoleChangesPacket
|
new GroupRoleChangesPacket
|
||||||
{
|
{
|
||||||
AgentData =
|
AgentData =
|
||||||
|
|
@ -1511,7 +1517,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="member">Avatar's ID to assign to role</param>
|
/// <param name="member">Avatar's ID to assign to role</param>
|
||||||
public void AddToRole(UUID group, UUID role, UUID member)
|
public void AddToRole(UUID group, UUID role, UUID member)
|
||||||
{
|
{
|
||||||
OpenMetaverse.Packets.GroupRoleChangesPacket grc =
|
GroupRoleChangesPacket grc =
|
||||||
new GroupRoleChangesPacket
|
new GroupRoleChangesPacket
|
||||||
{
|
{
|
||||||
AgentData =
|
AgentData =
|
||||||
|
|
@ -1536,7 +1542,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="group">Group ID to fetch notices for</param>
|
/// <param name="group">Group ID to fetch notices for</param>
|
||||||
public void RequestGroupNoticesList(UUID group)
|
public void RequestGroupNoticesList(UUID group)
|
||||||
{
|
{
|
||||||
OpenMetaverse.Packets.GroupNoticesListRequestPacket gnl =
|
GroupNoticesListRequestPacket gnl =
|
||||||
new GroupNoticesListRequestPacket
|
new GroupNoticesListRequestPacket
|
||||||
{
|
{
|
||||||
AgentData =
|
AgentData =
|
||||||
|
|
@ -1553,7 +1559,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="noticeID">ID of group notice</param>
|
/// <param name="noticeID">ID of group notice</param>
|
||||||
public void RequestGroupNotice(UUID noticeID)
|
public void RequestGroupNotice(UUID noticeID)
|
||||||
{
|
{
|
||||||
OpenMetaverse.Packets.GroupNoticeRequestPacket gnr =
|
GroupNoticeRequestPacket gnr =
|
||||||
new GroupNoticeRequestPacket
|
new GroupNoticeRequestPacket
|
||||||
{
|
{
|
||||||
AgentData =
|
AgentData =
|
||||||
|
|
@ -1618,43 +1624,21 @@ namespace OpenMetaverse
|
||||||
Client.Network.SendPacket(p);
|
Client.Network.SendPacket(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the URI of the cpability for handling group bans
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="groupID">Group ID</param>
|
|
||||||
/// <returns>null, if the feature is not supported, or URI of the capability</returns>
|
|
||||||
public Uri GetGroupAPIUri(UUID groupID)
|
|
||||||
{
|
|
||||||
Uri ret = null;
|
|
||||||
|
|
||||||
if (Client.Network.Connected)
|
|
||||||
{
|
|
||||||
ret = Client.Network.CurrentSim?.Caps?.CapabilityURI("GroupAPIv1");
|
|
||||||
if (ret != null)
|
|
||||||
{
|
|
||||||
ret = new Uri($"{ret}?group_id={groupID.ToString()}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request a list of residents banned from joining a group
|
/// Request a list of residents banned from joining a group
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="groupID">UUID of the group</param>
|
/// <param name="groupID">UUID of the group</param>
|
||||||
/// <param name="callback">Callback on request completion</param>
|
/// <param name="callback">Callback on request completion</param>
|
||||||
public async Task RequestBannedAgents(UUID groupID, EventHandler<BannedAgentsEventArgs> callback = null)
|
/// <param name="cancellationToken"></param>
|
||||||
|
public async Task RequestBannedAgents(UUID groupID, EventHandler<BannedAgentsEventArgs> callback = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
Uri uri = GetGroupAPIUri(groupID);
|
var uri = new UriBuilder(Client.Network.CurrentSim.Caps.CapabilityURI("GroupAPIv1"))
|
||||||
if (uri == null) { return; }
|
{Query = $"group_id={groupID}"}.Uri;
|
||||||
|
await Client.HttpCapsClient.GetRequestAsync(uri, cancellationToken, (response, data, error) =>
|
||||||
Uri cap = Client.Network.CurrentSim.Caps.CapabilityURI("GroupReqBanned");
|
|
||||||
await Client.HttpCapsClient.GetRequestAsync(cap, CancellationToken.None, (response, data, error) =>
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
if (error != null) { throw error; }
|
if (error != null) { throw error; }
|
||||||
|
|
||||||
OSD result = OSDParser.Deserialize(data);
|
OSD result = OSDParser.Deserialize(data);
|
||||||
|
|
@ -1677,7 +1661,7 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Log("Failed to get a list of banned group members: " + ex.Message, Helpers.LogLevel.Warning, Client);
|
Logger.Log($"Failed to fetch group ban list for {groupID}: {ex.Message}", Helpers.LogLevel.Warning, Client);
|
||||||
var ret = new BannedAgentsEventArgs(groupID, false, null);
|
var ret = new BannedAgentsEventArgs(groupID, false, null);
|
||||||
OnBannedAgents(ret);
|
OnBannedAgents(ret);
|
||||||
if (callback != null)
|
if (callback != null)
|
||||||
|
|
@ -1689,17 +1673,6 @@ namespace OpenMetaverse
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Request that group of agents be banned or unbanned from the group
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="groupID">Group ID</param>
|
|
||||||
/// <param name="action">Ban/Unban action</param>
|
|
||||||
/// <param name="agents">Array of agents UUIDs to ban</param>
|
|
||||||
public void RequestBanAction(UUID groupID, GroupBanAction action, UUID[] agents)
|
|
||||||
{
|
|
||||||
RequestBanAction(groupID, action, agents, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request that group of agents be banned or unbanned from the group
|
/// Request that group of agents be banned or unbanned from the group
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1707,26 +1680,28 @@ namespace OpenMetaverse
|
||||||
/// <param name="action">Ban/Unban action</param>
|
/// <param name="action">Ban/Unban action</param>
|
||||||
/// <param name="agents">Array of agents UUIDs to ban</param>
|
/// <param name="agents">Array of agents UUIDs to ban</param>
|
||||||
/// <param name="callback">Callback</param>
|
/// <param name="callback">Callback</param>
|
||||||
public void RequestBanAction(UUID groupID, GroupBanAction action, UUID[] agents, EventHandler<EventArgs> callback)
|
/// <param name="cancellationToken"></param>
|
||||||
|
public async Task RequestBanAction(UUID groupID, GroupBanAction action, UUID[] agents, EventHandler<EventArgs> callback = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
Uri baseCap = GetGroupAPIUri(groupID);
|
var uri = new UriBuilder(Client.Network.CurrentSim.Caps.CapabilityURI("GroupAPIv1")) {Query = $"group_id={groupID}"}.Uri;
|
||||||
if (baseCap == null)
|
|
||||||
{
|
|
||||||
Logger.Log("Unable to get Cap url for GroupAPIv1", Helpers.LogLevel.Warning, Client);
|
|
||||||
}
|
|
||||||
OSDMap payload = new OSDMap { ["ban_action"] = (int)action };
|
OSDMap payload = new OSDMap { ["ban_action"] = (int)action };
|
||||||
OSDArray banIDs = new OSDArray(agents.Length);
|
OSDArray banIDs = new OSDArray(agents.Length);
|
||||||
for (int i = 0; i < agents.Length; i++)
|
foreach (var agent in agents)
|
||||||
{
|
{
|
||||||
UUID agent = agents[i];
|
|
||||||
banIDs.Add(agent);
|
banIDs.Add(agent);
|
||||||
}
|
}
|
||||||
payload["ban_ids"] = banIDs;
|
payload["ban_ids"] = banIDs;
|
||||||
|
|
||||||
Task req = Client.HttpCapsClient.PostRequestAsync(baseCap, OSDFormat.Xml, payload, CancellationToken.None,
|
await Client.HttpCapsClient.PostRequestAsync(uri, OSDFormat.Xml, payload, cancellationToken,
|
||||||
(response, data, error) =>
|
(response, data, error) =>
|
||||||
{
|
{
|
||||||
if (error != null) { return; }
|
if (error != null)
|
||||||
|
{
|
||||||
|
Logger.Log($"Failed to ban members from {groupID}: {error.Message}", Helpers.LogLevel.Warning, Client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (callback != null)
|
if (callback != null)
|
||||||
{
|
{
|
||||||
try { callback(this, EventArgs.Empty); }
|
try { callback(this, EventArgs.Empty); }
|
||||||
|
|
@ -1746,14 +1721,16 @@ namespace OpenMetaverse
|
||||||
Dictionary<UUID, Group> currentGroups = new Dictionary<UUID, Group>();
|
Dictionary<UUID, Group> currentGroups = new Dictionary<UUID, Group>();
|
||||||
for (int i = 0; i < msg.GroupDataBlock.Length; i++)
|
for (int i = 0; i < msg.GroupDataBlock.Length; i++)
|
||||||
{
|
{
|
||||||
Group group = new Group();
|
Group group = new Group
|
||||||
group.ID = msg.GroupDataBlock[i].GroupID;
|
{
|
||||||
group.InsigniaID = msg.GroupDataBlock[i].GroupInsigniaID;
|
ID = msg.GroupDataBlock[i].GroupID,
|
||||||
group.Name = msg.GroupDataBlock[i].GroupName;
|
InsigniaID = msg.GroupDataBlock[i].GroupInsigniaID,
|
||||||
group.Contribution = msg.GroupDataBlock[i].Contribution;
|
Name = msg.GroupDataBlock[i].GroupName,
|
||||||
group.AcceptNotices = msg.GroupDataBlock[i].AcceptNotices;
|
Contribution = msg.GroupDataBlock[i].Contribution,
|
||||||
group.Powers = msg.GroupDataBlock[i].GroupPowers;
|
AcceptNotices = msg.GroupDataBlock[i].AcceptNotices,
|
||||||
group.ListInProfile = msg.NewGroupDataBlock[i].ListInProfile;
|
Powers = msg.GroupDataBlock[i].GroupPowers,
|
||||||
|
ListInProfile = msg.NewGroupDataBlock[i].ListInProfile
|
||||||
|
};
|
||||||
|
|
||||||
currentGroups.Add(group.ID, group);
|
currentGroups.Add(group.ID, group);
|
||||||
|
|
||||||
|
|
@ -1803,24 +1780,25 @@ namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
Packet packet = e.Packet;
|
Packet packet = e.Packet;
|
||||||
GroupProfileReplyPacket profile = (GroupProfileReplyPacket)packet;
|
GroupProfileReplyPacket profile = (GroupProfileReplyPacket)packet;
|
||||||
Group group = new Group();
|
Group group = new Group
|
||||||
|
{
|
||||||
group.ID = profile.GroupData.GroupID;
|
ID = profile.GroupData.GroupID,
|
||||||
group.AllowPublish = profile.GroupData.AllowPublish;
|
AllowPublish = profile.GroupData.AllowPublish,
|
||||||
group.Charter = Utils.BytesToString(profile.GroupData.Charter);
|
Charter = Utils.BytesToString(profile.GroupData.Charter),
|
||||||
group.FounderID = profile.GroupData.FounderID;
|
FounderID = profile.GroupData.FounderID,
|
||||||
group.GroupMembershipCount = profile.GroupData.GroupMembershipCount;
|
GroupMembershipCount = profile.GroupData.GroupMembershipCount,
|
||||||
group.GroupRolesCount = profile.GroupData.GroupRolesCount;
|
GroupRolesCount = profile.GroupData.GroupRolesCount,
|
||||||
group.InsigniaID = profile.GroupData.InsigniaID;
|
InsigniaID = profile.GroupData.InsigniaID,
|
||||||
group.MaturePublish = profile.GroupData.MaturePublish;
|
MaturePublish = profile.GroupData.MaturePublish,
|
||||||
group.MembershipFee = profile.GroupData.MembershipFee;
|
MembershipFee = profile.GroupData.MembershipFee,
|
||||||
group.MemberTitle = Utils.BytesToString(profile.GroupData.MemberTitle);
|
MemberTitle = Utils.BytesToString(profile.GroupData.MemberTitle),
|
||||||
group.Money = profile.GroupData.Money;
|
Money = profile.GroupData.Money,
|
||||||
group.Name = Utils.BytesToString(profile.GroupData.Name);
|
Name = Utils.BytesToString(profile.GroupData.Name),
|
||||||
group.OpenEnrollment = profile.GroupData.OpenEnrollment;
|
OpenEnrollment = profile.GroupData.OpenEnrollment,
|
||||||
group.OwnerRole = profile.GroupData.OwnerRole;
|
OwnerRole = profile.GroupData.OwnerRole,
|
||||||
group.Powers = (GroupPowers)profile.GroupData.PowersMask;
|
Powers = (GroupPowers)profile.GroupData.PowersMask,
|
||||||
group.ShowInList = profile.GroupData.ShowInList;
|
ShowInList = profile.GroupData.ShowInList
|
||||||
|
};
|
||||||
|
|
||||||
OnGroupProfile(new GroupProfileEventArgs(group));
|
OnGroupProfile(new GroupProfileEventArgs(group));
|
||||||
}
|
}
|
||||||
|
|
@ -1836,12 +1814,7 @@ namespace OpenMetaverse
|
||||||
Packet packet = e.Packet;
|
Packet packet = e.Packet;
|
||||||
GroupNoticesListReplyPacket reply = (GroupNoticesListReplyPacket)packet;
|
GroupNoticesListReplyPacket reply = (GroupNoticesListReplyPacket)packet;
|
||||||
|
|
||||||
List<GroupNoticesListEntry> notices = new List<GroupNoticesListEntry>();
|
List<GroupNoticesListEntry> notices = reply.Data.Select(entry => new GroupNoticesListEntry
|
||||||
|
|
||||||
foreach (GroupNoticesListReplyPacket.DataBlock entry in reply.Data)
|
|
||||||
{
|
|
||||||
GroupNoticesListEntry notice =
|
|
||||||
new GroupNoticesListEntry
|
|
||||||
{
|
{
|
||||||
FromName = Utils.BytesToString(entry.FromName),
|
FromName = Utils.BytesToString(entry.FromName),
|
||||||
Subject = Utils.BytesToString(entry.Subject),
|
Subject = Utils.BytesToString(entry.Subject),
|
||||||
|
|
@ -1849,10 +1822,8 @@ namespace OpenMetaverse
|
||||||
Timestamp = entry.Timestamp,
|
Timestamp = entry.Timestamp,
|
||||||
HasAttachment = entry.HasAttachment,
|
HasAttachment = entry.HasAttachment,
|
||||||
AssetType = (AssetType)entry.AssetType
|
AssetType = (AssetType)entry.AssetType
|
||||||
};
|
})
|
||||||
|
.ToList();
|
||||||
notices.Add(notice);
|
|
||||||
}
|
|
||||||
|
|
||||||
OnGroupNoticesListReply(new GroupNoticesListReplyEventArgs(reply.AgentData.GroupID, notices));
|
OnGroupNoticesListReply(new GroupNoticesListReplyEventArgs(reply.AgentData.GroupID, notices));
|
||||||
}
|
}
|
||||||
|
|
@ -2085,9 +2056,10 @@ namespace OpenMetaverse
|
||||||
/// <param name="e">The EventArgs object containing the packet data</param>
|
/// <param name="e">The EventArgs object containing the packet data</param>
|
||||||
protected void GroupActiveProposalItemHandler(object sender, PacketReceivedEventArgs e)
|
protected void GroupActiveProposalItemHandler(object sender, PacketReceivedEventArgs e)
|
||||||
{
|
{
|
||||||
//GroupActiveProposalItemReplyPacket proposal = (GroupActiveProposalItemReplyPacket)packet;
|
GroupActiveProposalItemReplyPacket proposal = (GroupActiveProposalItemReplyPacket)e.Packet;
|
||||||
|
|
||||||
// TODO: Create a proposal struct to represent the fields in a proposal item
|
// NOTE: Second Life server removed this many years back.
|
||||||
|
Logger.Log($"Received GroupActiveProposalItemReplyPacket: {proposal}", Helpers.LogLevel.Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Process an incoming packet and raise the appropriate events</summary>
|
/// <summary>Process an incoming packet and raise the appropriate events</summary>
|
||||||
|
|
@ -2095,9 +2067,10 @@ namespace OpenMetaverse
|
||||||
/// <param name="e">The EventArgs object containing the packet data</param>
|
/// <param name="e">The EventArgs object containing the packet data</param>
|
||||||
protected void GroupVoteHistoryItemHandler(object sender, PacketReceivedEventArgs e)
|
protected void GroupVoteHistoryItemHandler(object sender, PacketReceivedEventArgs e)
|
||||||
{
|
{
|
||||||
//GroupVoteHistoryItemReplyPacket history = (GroupVoteHistoryItemReplyPacket)packet;
|
GroupVoteHistoryItemReplyPacket history = (GroupVoteHistoryItemReplyPacket)e.Packet;
|
||||||
|
|
||||||
// TODO: This was broken in the official viewer when I was last trying to work on it
|
// NOTE: Second Life server removed this many years back.
|
||||||
|
Logger.Log($"Received GroupVoteHistoryItemReplyPacket: {history}", Helpers.LogLevel.Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Process an incoming packet and raise the appropriate events</summary>
|
/// <summary>Process an incoming packet and raise the appropriate events</summary>
|
||||||
|
|
@ -2235,7 +2208,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="groups">The current groups your agent is a member of</param>
|
/// <param name="groups">The current groups your agent is a member of</param>
|
||||||
public CurrentGroupsEventArgs(Dictionary<UUID, Group> groups)
|
public CurrentGroupsEventArgs(Dictionary<UUID, Group> groups)
|
||||||
{
|
{
|
||||||
this.Groups = groups;
|
Groups = groups;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2249,7 +2222,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="groupNames">The Group names dictionary</param>
|
/// <param name="groupNames">The Group names dictionary</param>
|
||||||
public GroupNamesEventArgs(Dictionary<UUID, string> groupNames)
|
public GroupNamesEventArgs(Dictionary<UUID, string> groupNames)
|
||||||
{
|
{
|
||||||
this.GroupNames = groupNames;
|
GroupNames = groupNames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2274,9 +2247,9 @@ namespace OpenMetaverse
|
||||||
/// <param name="members">The membership list of the group</param>
|
/// <param name="members">The membership list of the group</param>
|
||||||
public GroupMembersReplyEventArgs(UUID requestID, UUID groupID, Dictionary<UUID, GroupMember> members)
|
public GroupMembersReplyEventArgs(UUID requestID, UUID groupID, Dictionary<UUID, GroupMember> members)
|
||||||
{
|
{
|
||||||
this.RequestID = requestID;
|
RequestID = requestID;
|
||||||
this.GroupID = groupID;
|
GroupID = groupID;
|
||||||
this.Members = members;
|
Members = members;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2300,9 +2273,9 @@ namespace OpenMetaverse
|
||||||
/// <param name="roles">The dictionary containing the roles</param>
|
/// <param name="roles">The dictionary containing the roles</param>
|
||||||
public GroupRolesDataReplyEventArgs(UUID requestID, UUID groupID, Dictionary<UUID, GroupRole> roles)
|
public GroupRolesDataReplyEventArgs(UUID requestID, UUID groupID, Dictionary<UUID, GroupRole> roles)
|
||||||
{
|
{
|
||||||
this.RequestID = requestID;
|
RequestID = requestID;
|
||||||
this.GroupID = groupID;
|
GroupID = groupID;
|
||||||
this.Roles = roles;
|
Roles = roles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2326,9 +2299,9 @@ namespace OpenMetaverse
|
||||||
/// <param name="rolesMembers">The member to roles map</param>
|
/// <param name="rolesMembers">The member to roles map</param>
|
||||||
public GroupRolesMembersReplyEventArgs(UUID requestID, UUID groupID, List<KeyValuePair<UUID, UUID>> rolesMembers)
|
public GroupRolesMembersReplyEventArgs(UUID requestID, UUID groupID, List<KeyValuePair<UUID, UUID>> rolesMembers)
|
||||||
{
|
{
|
||||||
this.RequestID = requestID;
|
RequestID = requestID;
|
||||||
this.GroupID = groupID;
|
GroupID = groupID;
|
||||||
this.RolesMembers = rolesMembers;
|
RolesMembers = rolesMembers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2352,9 +2325,9 @@ namespace OpenMetaverse
|
||||||
/// <param name="titles">The titles</param>
|
/// <param name="titles">The titles</param>
|
||||||
public GroupTitlesReplyEventArgs(UUID requestID, UUID groupID, Dictionary<UUID, GroupTitle> titles)
|
public GroupTitlesReplyEventArgs(UUID requestID, UUID groupID, Dictionary<UUID, GroupTitle> titles)
|
||||||
{
|
{
|
||||||
this.RequestID = requestID;
|
RequestID = requestID;
|
||||||
this.GroupID = groupID;
|
GroupID = groupID;
|
||||||
this.Titles = titles;
|
Titles = titles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2372,8 +2345,8 @@ namespace OpenMetaverse
|
||||||
/// <param name="summary">The summary data</param>
|
/// <param name="summary">The summary data</param>
|
||||||
public GroupAccountSummaryReplyEventArgs(UUID groupID, GroupAccountSummary summary)
|
public GroupAccountSummaryReplyEventArgs(UUID groupID, GroupAccountSummary summary)
|
||||||
{
|
{
|
||||||
this.GroupID = groupID;
|
GroupID = groupID;
|
||||||
this.Summary = summary;
|
Summary = summary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2391,13 +2364,13 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
/// <summary>Construct a new instance of the GroupCreatedReplyEventArgs class</summary>
|
/// <summary>Construct a new instance of the GroupCreatedReplyEventArgs class</summary>
|
||||||
/// <param name="groupID">The ID of the group</param>
|
/// <param name="groupID">The ID of the group</param>
|
||||||
/// <param name="success">the success or faulure of the request</param>
|
/// <param name="success">the success or failure of the request</param>
|
||||||
/// <param name="messsage">A string containing additional information</param>
|
/// <param name="message">A string containing additional information</param>
|
||||||
public GroupCreatedReplyEventArgs(UUID groupID, bool success, string messsage)
|
public GroupCreatedReplyEventArgs(UUID groupID, bool success, string message)
|
||||||
{
|
{
|
||||||
this.GroupID = groupID;
|
GroupID = groupID;
|
||||||
this.Success = success;
|
Success = success;
|
||||||
this.Message = messsage;
|
Message = message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2415,8 +2388,8 @@ namespace OpenMetaverse
|
||||||
/// <param name="success">true of the request was successful</param>
|
/// <param name="success">true of the request was successful</param>
|
||||||
public GroupOperationEventArgs(UUID groupID, bool success)
|
public GroupOperationEventArgs(UUID groupID, bool success)
|
||||||
{
|
{
|
||||||
this.GroupID = groupID;
|
GroupID = groupID;
|
||||||
this.Success = success;
|
Success = success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2463,7 +2436,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="group">The group profile</param>
|
/// <param name="group">The group profile</param>
|
||||||
public GroupProfileEventArgs(Group group)
|
public GroupProfileEventArgs(Group group)
|
||||||
{
|
{
|
||||||
this.Group = group;
|
Group = group;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2492,10 +2465,10 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
public GroupInvitationEventArgs(Simulator simulator, UUID agentID, string agentName, string message)
|
public GroupInvitationEventArgs(Simulator simulator, UUID agentID, string agentName, string message)
|
||||||
{
|
{
|
||||||
this.Simulator = simulator;
|
Simulator = simulator;
|
||||||
this.AgentID = agentID;
|
AgentID = agentID;
|
||||||
this.FromName = agentName;
|
FromName = agentName;
|
||||||
this.Message = message;
|
Message = message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2515,9 +2488,9 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
public BannedAgentsEventArgs(UUID groupID, bool success, Dictionary<UUID, DateTime> bannedAgents)
|
public BannedAgentsEventArgs(UUID groupID, bool success, Dictionary<UUID, DateTime> bannedAgents)
|
||||||
{
|
{
|
||||||
this.GroupID = groupID;
|
GroupID = groupID;
|
||||||
this.Success = success;
|
Success = success;
|
||||||
this.BannedAgents = bannedAgents;
|
BannedAgents = bannedAgents;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007-2008, openmetaverse.co
|
* Copyright (c) 2007-2008, openmetaverse.co
|
||||||
* Copyright (c) 2024, Sjofn LLC.
|
* Copyright (c) 2024-2025, Sjofn LLC.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* - Redistribution and use in source and binary forms, with or without
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
|
|
@ -360,7 +360,7 @@ namespace OpenMetaverse.Imaging
|
||||||
SKBitmap bitmap = null;
|
SKBitmap bitmap = null;
|
||||||
lock (ResourceSync)
|
lock (ResourceSync)
|
||||||
{
|
{
|
||||||
using (Stream stream = Helpers.GetResourceStream(fileName, Settings.RESOURCE_DIR))
|
using (Stream stream = Helpers.GetResourceStream(fileName, Path.Combine(Settings.RESOURCE_DIR, "static_assets")))
|
||||||
{
|
{
|
||||||
if (stream != null)
|
if (stream != null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ namespace OpenMetaverse.Imaging
|
||||||
tga[di++] = c.Green;
|
tga[di++] = c.Green;
|
||||||
tga[di++] = c.Red;
|
tga[di++] = c.Red;
|
||||||
|
|
||||||
tga[di++] = (byte)(image.AlphaType > SKAlphaType.Opaque ? 0x0 : c.Alpha);
|
tga[di++] = (byte)(image.AlphaType > SKAlphaType.Opaque ? c.Alpha : 0x0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,32 @@ namespace OpenMetaverse
|
||||||
Items = new ConcurrentDictionary<UUID, InventoryNode>();
|
Items = new ConcurrentDictionary<UUID, InventoryNode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns all links of that link the specific <paramref name="assertId"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assertId">An inventory items assert UUID.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<InventoryNode> FindAllLinks(UUID assertId)
|
||||||
|
{
|
||||||
|
List<InventoryNode> links = new List<InventoryNode>();
|
||||||
|
lock (RootNode.Nodes.SyncRoot)
|
||||||
|
{
|
||||||
|
links = Items.Values.Where(node => IsLinkOf(node, assertId)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsLinkOf(InventoryNode node, UUID assertId)
|
||||||
|
{
|
||||||
|
if (node.Data is InventoryItem item && item.AssetType == AssetType.Link)
|
||||||
|
{
|
||||||
|
return item.ActualUUID == assertId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public List<InventoryBase> GetContents(InventoryFolder folder)
|
public List<InventoryBase> GetContents(InventoryFolder folder)
|
||||||
{
|
{
|
||||||
return GetContents(folder.UUID);
|
return GetContents(folder.UUID);
|
||||||
|
|
@ -487,7 +513,6 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Operators
|
#endregion Operators
|
||||||
|
|
||||||
}
|
}
|
||||||
#region EventArgs classes
|
#region EventArgs classes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -443,7 +443,11 @@ namespace OpenMetaverse
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
private readonly GridClient Client;
|
private readonly GridClient Client;
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
public Inventory _Store;
|
private Inventory _Store;
|
||||||
|
public Inventory GetStore
|
||||||
|
{
|
||||||
|
get { return _Store; }
|
||||||
|
}
|
||||||
private object _CallbacksLock = new object();
|
private object _CallbacksLock = new object();
|
||||||
private uint _CallbackPos;
|
private uint _CallbackPos;
|
||||||
private readonly Dictionary<uint, ItemCreatedCallback> _ItemCreatedCallbacks = new Dictionary<uint, ItemCreatedCallback>();
|
private readonly Dictionary<uint, ItemCreatedCallback> _ItemCreatedCallbacks = new Dictionary<uint, ItemCreatedCallback>();
|
||||||
|
|
@ -529,7 +533,7 @@ namespace OpenMetaverse
|
||||||
InventoryItem item = null;
|
InventoryItem item = null;
|
||||||
await RequestFetchInventoryHttpAsync(itemId, ownerId, token, list =>
|
await RequestFetchInventoryHttpAsync(itemId, ownerId, token, list =>
|
||||||
{
|
{
|
||||||
item = list.First();
|
item = list.FirstOrDefault();
|
||||||
});
|
});
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
@ -1780,6 +1784,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="folderID">Put newly created link in folder with this UUID</param>
|
/// <param name="folderID">Put newly created link in folder with this UUID</param>
|
||||||
/// <param name="bse">Inventory item or folder</param>
|
/// <param name="bse">Inventory item or folder</param>
|
||||||
/// <param name="callback">Method to call upon creation of the link</param>
|
/// <param name="callback">Method to call upon creation of the link</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
public void CreateLink(UUID folderID, InventoryBase bse, ItemCreatedCallback callback, CancellationToken cancellationToken = default)
|
public void CreateLink(UUID folderID, InventoryBase bse, ItemCreatedCallback callback, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (bse is InventoryFolder folder)
|
if (bse is InventoryFolder folder)
|
||||||
|
|
@ -1798,6 +1803,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="folderID">Put newly created link in folder with this UUID</param>
|
/// <param name="folderID">Put newly created link in folder with this UUID</param>
|
||||||
/// <param name="item">Original inventory item</param>
|
/// <param name="item">Original inventory item</param>
|
||||||
/// <param name="callback">Method to call upon creation of the link</param>
|
/// <param name="callback">Method to call upon creation of the link</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
public void CreateLink(UUID folderID, InventoryItem item, ItemCreatedCallback callback, CancellationToken cancellationToken = default)
|
public void CreateLink(UUID folderID, InventoryItem item, ItemCreatedCallback callback, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
CreateLink(folderID, item.UUID, item.Name, item.Description, item.InventoryType, UUID.Random(), callback, cancellationToken);
|
CreateLink(folderID, item.UUID, item.Name, item.Description, item.InventoryType, UUID.Random(), callback, cancellationToken);
|
||||||
|
|
@ -1809,6 +1815,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="folderID">Put newly created link in folder with this UUID</param>
|
/// <param name="folderID">Put newly created link in folder with this UUID</param>
|
||||||
/// <param name="folder">Original inventory folder</param>
|
/// <param name="folder">Original inventory folder</param>
|
||||||
/// <param name="callback">Method to call upon creation of the link</param>
|
/// <param name="callback">Method to call upon creation of the link</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
public void CreateLink(UUID folderID, InventoryFolder folder, ItemCreatedCallback callback, CancellationToken cancellationToken = default)
|
public void CreateLink(UUID folderID, InventoryFolder folder, ItemCreatedCallback callback, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
CreateLink(folderID, folder.UUID, folder.Name, "", InventoryType.Folder, UUID.Random(), callback, cancellationToken);
|
CreateLink(folderID, folder.UUID, folder.Name, "", InventoryType.Folder, UUID.Random(), callback, cancellationToken);
|
||||||
|
|
@ -1824,6 +1831,7 @@ namespace OpenMetaverse
|
||||||
/// <param name="invType">Inventory Type</param>
|
/// <param name="invType">Inventory Type</param>
|
||||||
/// <param name="transactionID">Transaction UUID</param>
|
/// <param name="transactionID">Transaction UUID</param>
|
||||||
/// <param name="callback">Method to call upon creation of the link</param>
|
/// <param name="callback">Method to call upon creation of the link</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
public void CreateLink(UUID folderID, UUID itemID, string name, string description,
|
public void CreateLink(UUID folderID, UUID itemID, string name, string description,
|
||||||
InventoryType invType, UUID transactionID, ItemCreatedCallback callback, CancellationToken cancellationToken = default)
|
InventoryType invType, UUID transactionID, ItemCreatedCallback callback, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -26,15 +26,15 @@
|
||||||
<Optimize>True</Optimize>
|
<Optimize>True</Optimize>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CoreJ2K.Skia" Version="1.1.1.48" />
|
<PackageReference Include="CoreJ2K.Skia" Version="1.1.2.50" />
|
||||||
<PackageReference Include="log4net" Version="3.1.0" />
|
<PackageReference Include="log4net" Version="3.2.0" />
|
||||||
<PackageReference Include="MessagePack" Version="3.1.4" />
|
<PackageReference Include="MessagePack" Version="3.1.4" />
|
||||||
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.6" />
|
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.8" />
|
||||||
<PackageReference Include="OggVorbisEncoder" Version="1.2.2" />
|
<PackageReference Include="OggVorbisEncoder" Version="1.2.2" />
|
||||||
<PackageReference Include="Pfim" Version="0.11.3" />
|
<PackageReference Include="Pfim" Version="0.11.3" />
|
||||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||||
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
|
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="9.0.6" />
|
<PackageReference Include="System.Threading.Channels" Version="9.0.8" />
|
||||||
<PackageReference Include="XmlRpcCore" Version="3.1.3" />
|
<PackageReference Include="XmlRpcCore" Version="3.1.3" />
|
||||||
<PackageReference Include="zlib.net-mutliplatform" Version="1.0.8" />
|
<PackageReference Include="zlib.net-mutliplatform" Version="1.0.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
@ -42,6 +42,14 @@
|
||||||
<ProjectReference Include="..\LibreMetaverse.StructuredData\LibreMetaverse.StructuredData.csproj" />
|
<ProjectReference Include="..\LibreMetaverse.StructuredData\LibreMetaverse.StructuredData.csproj" />
|
||||||
<ProjectReference Include="..\LibreMetaverse.Types\LibreMetaverse.Types.csproj" />
|
<ProjectReference Include="..\LibreMetaverse.Types\LibreMetaverse.Types.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="linden\**" Pack="true">
|
||||||
|
<PackagePath>contentFiles\any\any\linden;content\linden</PackagePath>
|
||||||
|
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\LICENSE.txt" Pack="true" PackagePath="\" />
|
<None Include="..\LICENSE.txt" Pack="true" PackagePath="\" />
|
||||||
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
||||||
|
|
|
||||||
381
LibreMetaverse/LslSyntax.cs
Normal file
381
LibreMetaverse/LslSyntax.cs
Normal file
|
|
@ -0,0 +1,381 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Sjofn LLC.
|
||||||
|
* 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.
|
||||||
|
* - Neither the name of the openmetaverse.co 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 OWNER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Frozen;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenMetaverse.StructuredData;
|
||||||
|
using Logger = OpenMetaverse.Logger;
|
||||||
|
|
||||||
|
namespace LibreMetaverse
|
||||||
|
{
|
||||||
|
public class LslSyntax
|
||||||
|
{
|
||||||
|
public enum LslCategory
|
||||||
|
{
|
||||||
|
Function,
|
||||||
|
Control,
|
||||||
|
Event,
|
||||||
|
Datatype,
|
||||||
|
Constant,
|
||||||
|
Flow,
|
||||||
|
Unknown = -1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct LslKeyword
|
||||||
|
{
|
||||||
|
public LslCategory Category;
|
||||||
|
public string Keyword;
|
||||||
|
public string Tooltip;
|
||||||
|
public bool Deprecated;
|
||||||
|
public bool GodMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string KEYWORDS_DEFAULT = "keywords_lsl_default.xml";
|
||||||
|
private const string VERSION_KEY = "llsd-lsl-syntax-version";
|
||||||
|
private const string SYNTAX_FEATURE_IDENTIFIER = "LSLSyntaxId";
|
||||||
|
private const string SYNTAX_CAPABILITY_IDENTIFIER = "LSLSyntax";
|
||||||
|
|
||||||
|
private static Dictionary<string, LslKeyword> _keywords = new Dictionary<string, LslKeyword>();
|
||||||
|
public static FrozenDictionary<string, LslKeyword> Keywords => _keywords.ToFrozenDictionary();
|
||||||
|
|
||||||
|
private GridClient _client;
|
||||||
|
private UUID _syntaxId;
|
||||||
|
|
||||||
|
#region EVENTS
|
||||||
|
|
||||||
|
/// <summary>The event subscribers, null if no subscribers</summary>
|
||||||
|
private EventHandler _syntaxChanged;
|
||||||
|
|
||||||
|
///<summary>Raises the SyntaxChanged Event</summary>
|
||||||
|
protected void OnSyntaxChanged()
|
||||||
|
{
|
||||||
|
EventHandler handler = _syntaxChanged;
|
||||||
|
handler?.Invoke(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Thread sync lock object</summary>
|
||||||
|
private readonly object _syntaxChangedLock = new object();
|
||||||
|
|
||||||
|
/// <summary>Raised when the syntax tokens are updated</summary>
|
||||||
|
public event EventHandler SyntaxChanged
|
||||||
|
{
|
||||||
|
add { lock (_syntaxChangedLock) { _syntaxChanged += value; } }
|
||||||
|
remove { lock (_syntaxChangedLock) { _syntaxChanged -= value; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion EVENTS
|
||||||
|
|
||||||
|
public LslSyntax()
|
||||||
|
{
|
||||||
|
var keywordFile = Path.Combine(Settings.RESOURCE_DIR, KEYWORDS_DEFAULT);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (FileStream fs = new FileStream(keywordFile, FileMode.Open, FileAccess.Read))
|
||||||
|
{
|
||||||
|
ParseFile(fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
Logger.Log($"Failed to find {keywordFile}.", Helpers.LogLevel.Warning);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
Logger.Log($"Failed to read {keywordFile}: {e.Message}", Helpers.LogLevel.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LslSyntax(GridClient client)
|
||||||
|
{
|
||||||
|
Register(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Register(GridClient client)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
|
||||||
|
var keywordFile = Path.Combine(Settings.RESOURCE_DIR, KEYWORDS_DEFAULT);
|
||||||
|
if (_client.Network.Connected && _client.Network.CurrentSim.Features != null)
|
||||||
|
{
|
||||||
|
var syntaxId = _client.Network.CurrentSim.Features.Get(SYNTAX_FEATURE_IDENTIFIER);
|
||||||
|
if (syntaxId != null && syntaxId.Type == OSDType.UUID)
|
||||||
|
{
|
||||||
|
var file = Path.Combine(_client.Settings.ASSET_CACHE_DIR, $"keywords_lsl_{syntaxId}.xml");
|
||||||
|
if (File.Exists(file))
|
||||||
|
{
|
||||||
|
keywordFile = file;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var uri = _client.Network.CurrentSim.Caps.CapabilityURI(SYNTAX_CAPABILITY_IDENTIFIER);
|
||||||
|
if (uri != null)
|
||||||
|
{
|
||||||
|
Task fetch = _client.Network.CurrentSim.Client.HttpCapsClient.GetRequestAsync(uri,
|
||||||
|
CancellationToken.None, (response, data, error) =>
|
||||||
|
{
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
Logger.Log($"Failed to retrieve syntax file. Error: {error.Message}",
|
||||||
|
Helpers.LogLevel.Warning, _client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Logger.Log(
|
||||||
|
$"Failed to retrieve syntax file. Status: {response.StatusCode} {response.ReasonPhrase}",
|
||||||
|
Helpers.LogLevel.Warning, _client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSD features = OSDParser.Deserialize(data);
|
||||||
|
if (features.Type != OSDType.Map)
|
||||||
|
{
|
||||||
|
Logger.Log("Invalid format for syntax file. Root element is not a map.",
|
||||||
|
Helpers.LogLevel.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parse((OSDMap)features);
|
||||||
|
_syntaxId = syntaxId;
|
||||||
|
using (FileStream writer =
|
||||||
|
new FileStream(
|
||||||
|
Path.Combine(_client.Settings.ASSET_CACHE_DIR,
|
||||||
|
$"keywords_lsl_{syntaxId}.xml"),
|
||||||
|
FileMode.Create, FileAccess.Write))
|
||||||
|
{
|
||||||
|
var bytes = OSDParser.SerializeLLSDXmlBytes(features);
|
||||||
|
writer.Write(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fetch.Wait(TimeSpan.FromSeconds(20));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (FileStream fs = new FileStream(keywordFile, FileMode.Open, FileAccess.Read))
|
||||||
|
{
|
||||||
|
ParseFile(fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
Logger.Log($"Failed to find {keywordFile}.", Helpers.LogLevel.Warning);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
Logger.Log($"Failed to read {keywordFile}: {e.Message}", Helpers.LogLevel.Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
_client.Network.SimChanged += Network_OnSimChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Network_OnSimChanged(object sender, SimChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_client.Network.CurrentSim.Caps.CapabilitiesReceived += Simulator_OnCapabilitiesReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Simulator_OnCapabilitiesReceived(object sender, CapabilitiesReceivedEventArgs e)
|
||||||
|
{
|
||||||
|
e.Simulator.Caps.CapabilitiesReceived -= Simulator_OnCapabilitiesReceived;
|
||||||
|
|
||||||
|
var syntaxId = e.Simulator.Features.Get(SYNTAX_FEATURE_IDENTIFIER);
|
||||||
|
var uri = e.Simulator.Caps.CapabilityURI(SYNTAX_CAPABILITY_IDENTIFIER);
|
||||||
|
if (uri == null || syntaxId == null || syntaxId.Type != OSDType.UUID) { return; }
|
||||||
|
if (syntaxId.AsUUID() == _syntaxId) { return; }
|
||||||
|
|
||||||
|
_ = e.Simulator.Client.HttpCapsClient.GetRequestAsync(uri, CancellationToken.None, (response, data, error) =>
|
||||||
|
{
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
Logger.Log($"Failed to retrieve syntax file. Error: {error.Message}", Helpers.LogLevel.Warning, _client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Logger.Log($"Failed to retrieve syntax file. Status: {response.StatusCode} {response.ReasonPhrase}",
|
||||||
|
Helpers.LogLevel.Warning, _client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OSD features = OSDParser.Deserialize(data);
|
||||||
|
if (features.Type != OSDType.Map)
|
||||||
|
{
|
||||||
|
Logger.Log("Invalid format for syntax file. Root element is not a map.", Helpers.LogLevel.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Parse((OSDMap)features);
|
||||||
|
_syntaxId = syntaxId;
|
||||||
|
using (FileStream writer =
|
||||||
|
new FileStream(Path.Combine(_client.Settings.ASSET_CACHE_DIR, $"keywords_lsl_{syntaxId}.xml"),
|
||||||
|
FileMode.Create, FileAccess.Write))
|
||||||
|
{
|
||||||
|
var bytes = OSDParser.SerializeLLSDXmlBytes(features);
|
||||||
|
writer.Write(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseFile(Stream stream)
|
||||||
|
{
|
||||||
|
using (XmlTextReader reader = new XmlTextReader(stream))
|
||||||
|
{
|
||||||
|
var deserialized = OSDParser.DeserializeLLSDXml(reader);
|
||||||
|
if (deserialized.Type != OSDType.Map)
|
||||||
|
{
|
||||||
|
Logger.Log("Invalid format for syntax file. Root element is not a map.", Helpers.LogLevel.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Parse((OSDMap)deserialized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Parse(OSDMap map)
|
||||||
|
{
|
||||||
|
if (!map.TryGetValue(VERSION_KEY, out var version))
|
||||||
|
{
|
||||||
|
Logger.Log("Syntax file does not contain a version key. Contents may not parse correctly.",
|
||||||
|
Helpers.LogLevel.Warning);
|
||||||
|
}
|
||||||
|
else if (version.AsInteger() != 2)
|
||||||
|
{
|
||||||
|
Logger.Log($"Syntax file version {version.AsInteger()} is incompatible. Contents may not parse correctly.",
|
||||||
|
Helpers.LogLevel.Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tokens = 0, added = 0;
|
||||||
|
var keywords = new Dictionary<string, LslKeyword>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var groupEnumerator = map.GetEnumerator();
|
||||||
|
while (groupEnumerator.MoveNext())
|
||||||
|
{
|
||||||
|
var group = (string)groupEnumerator.Key;
|
||||||
|
if (group == VERSION_KEY) { continue; }
|
||||||
|
|
||||||
|
var items = (OSDMap)groupEnumerator.Value;
|
||||||
|
|
||||||
|
var enumerator = items.GetEnumerator();
|
||||||
|
while (enumerator.MoveNext())
|
||||||
|
{
|
||||||
|
++tokens;
|
||||||
|
StringBuilder tooltip = new StringBuilder();
|
||||||
|
LslCategory category = LslCategory.Unknown;
|
||||||
|
var key = (string)enumerator.Key;
|
||||||
|
var attr = (OSDMap)enumerator.Value;
|
||||||
|
|
||||||
|
tooltip.AppendLine(attr["tooltip"].AsString());
|
||||||
|
|
||||||
|
switch (group)
|
||||||
|
{
|
||||||
|
case "controls":
|
||||||
|
category = LslCategory.Control;
|
||||||
|
break;
|
||||||
|
case "types":
|
||||||
|
category = LslCategory.Datatype;
|
||||||
|
break;
|
||||||
|
case "constants":
|
||||||
|
category = LslCategory.Constant;
|
||||||
|
tooltip.Append($" Type: {attr["type"]}-{attr["value"]}");
|
||||||
|
break;
|
||||||
|
case "events":
|
||||||
|
category = LslCategory.Event;
|
||||||
|
tooltip.Append($"{key} ({ParseArguments(attr["arguments"])})");
|
||||||
|
break;
|
||||||
|
case "functions":
|
||||||
|
category = LslCategory.Function;
|
||||||
|
tooltip.AppendLine(
|
||||||
|
$"{attr["return"]} {key} ({ParseArguments(attr["arguments"])})");
|
||||||
|
tooltip.Append(
|
||||||
|
$"Energy: {(attr.ContainsKey("energy") ? attr["energy"].AsString() : "0.0")}");
|
||||||
|
if (attr.TryGetValue("sleep", out var sleep))
|
||||||
|
tooltip.Append($", Sleep: {sleep}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (category == LslCategory.Unknown) { continue; }
|
||||||
|
|
||||||
|
var kw = new LslKeyword
|
||||||
|
{
|
||||||
|
Category = category,
|
||||||
|
Keyword = key,
|
||||||
|
Deprecated = attr.ContainsKey("deprecated") && attr["deprecated"].AsBoolean(),
|
||||||
|
GodMode = attr.ContainsKey("god-mode") && attr["god-mode"].AsBoolean(),
|
||||||
|
Tooltip = tooltip.ToString(),
|
||||||
|
};
|
||||||
|
keywords.Add(kw.Keyword, kw);
|
||||||
|
++added;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Log($"Syntax parser exception: {e.Message}", Helpers.LogLevel.Warning);
|
||||||
|
}
|
||||||
|
Logger.Log($"Parsed Syntax file, added {added}/{tokens} tokens.", Helpers.LogLevel.Debug);
|
||||||
|
lock(_keywords) { _keywords = keywords; }
|
||||||
|
OnSyntaxChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ParseArguments(OSD args)
|
||||||
|
{
|
||||||
|
var str = new StringBuilder();
|
||||||
|
if (args.Type == OSDType.Array)
|
||||||
|
{
|
||||||
|
foreach (var osd in (OSDArray)args)
|
||||||
|
{
|
||||||
|
if (osd.Type == OSDType.Map)
|
||||||
|
{
|
||||||
|
var map = (OSDMap)osd;
|
||||||
|
var left = map.Count;
|
||||||
|
var enumerable = map.GetEnumerator();
|
||||||
|
while (enumerable.MoveNext())
|
||||||
|
{
|
||||||
|
var value = (OSD)enumerable.Value;
|
||||||
|
str.Append($"{value.AsString()} {(string)enumerable.Key}");
|
||||||
|
if (left-- > 1)
|
||||||
|
{
|
||||||
|
str.Append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,17 +25,18 @@
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using LibreMetaverse;
|
||||||
|
using OpenMetaverse.Interfaces;
|
||||||
|
using OpenMetaverse.Messages.Linden;
|
||||||
|
using OpenMetaverse.Packets;
|
||||||
|
using OpenMetaverse.StructuredData;
|
||||||
|
using SkiaSharp;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenMetaverse.Packets;
|
using System.Reflection;
|
||||||
using OpenMetaverse.Interfaces;
|
using System.Threading;
|
||||||
using OpenMetaverse.StructuredData;
|
|
||||||
using OpenMetaverse.Messages.Linden;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LibreMetaverse;
|
|
||||||
|
|
||||||
namespace OpenMetaverse
|
namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
|
|
@ -616,6 +617,102 @@ namespace OpenMetaverse
|
||||||
Update(client, client.Network.CurrentSim, wantReply);
|
Update(client, client.Network.CurrentSim, wantReply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateParcelAccessList(
|
||||||
|
GridClient Client,
|
||||||
|
AccessList flags,
|
||||||
|
List<ParcelManager.ParcelAccessEntry> entries)
|
||||||
|
{
|
||||||
|
if(Client == null) throw new InvalidOperationException("Client is null");
|
||||||
|
if(Client.Network == null) throw new InvalidOperationException("Client.Network is null");
|
||||||
|
if(Client.Network.CurrentSim == null) throw new InvalidOperationException("Client.Network.CurrentSim is null");
|
||||||
|
Simulator simulator = Client.Network.CurrentSim;
|
||||||
|
if (simulator == null) throw new InvalidOperationException("No current simulator");
|
||||||
|
int parcelLocalId = LocalID;
|
||||||
|
if (parcelLocalId == 0) throw new InvalidOperationException("Parcel LocalID is zero");
|
||||||
|
if (entries.Count == 0)
|
||||||
|
{
|
||||||
|
// send an empty block to clear the list
|
||||||
|
Guid sendemptyGuid = Guid.NewGuid();
|
||||||
|
var packet = new ParcelAccessListUpdatePacket
|
||||||
|
{
|
||||||
|
AgentData = {
|
||||||
|
AgentID = Client.Self.AgentID,
|
||||||
|
SessionID = Client.Self.SessionID
|
||||||
|
},
|
||||||
|
Data = {
|
||||||
|
Flags = (uint)flags,
|
||||||
|
LocalID = parcelLocalId,
|
||||||
|
TransactionID = new UUID(sendemptyGuid.ToString()),
|
||||||
|
SequenceID = 1,
|
||||||
|
Sections = 0
|
||||||
|
},
|
||||||
|
List = { }
|
||||||
|
};
|
||||||
|
packet.List = new ParcelAccessListUpdatePacket.ListBlock[1];
|
||||||
|
packet.List[0] = new ParcelAccessListUpdatePacket.ListBlock
|
||||||
|
{
|
||||||
|
ID = UUID.Zero,
|
||||||
|
Time = 0,
|
||||||
|
Flags = 0
|
||||||
|
};
|
||||||
|
simulator.SendPacket(packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int PARCEL_MAX_ENTRIES_PER_PACKET = 48; // Set to your actual max
|
||||||
|
int count = entries.Count;
|
||||||
|
int numSections = (int)Math.Ceiling((double)count / PARCEL_MAX_ENTRIES_PER_PACKET);
|
||||||
|
int sequenceId = 1;
|
||||||
|
Guid transactionUUID = Guid.NewGuid();
|
||||||
|
int entryIndex = 0;
|
||||||
|
for (int section = 0; section < numSections; section++)
|
||||||
|
{
|
||||||
|
var packet = new ParcelAccessListUpdatePacket
|
||||||
|
{
|
||||||
|
AgentData = {
|
||||||
|
AgentID = Client.Self.AgentID,
|
||||||
|
SessionID = Client.Self.SessionID
|
||||||
|
},
|
||||||
|
Data = {
|
||||||
|
Flags = (uint)flags,
|
||||||
|
LocalID = parcelLocalId,
|
||||||
|
TransactionID = new UUID(transactionUUID.ToString()),
|
||||||
|
SequenceID = sequenceId,
|
||||||
|
Sections = numSections
|
||||||
|
},
|
||||||
|
List = new ParcelAccessListUpdatePacket.ListBlock[
|
||||||
|
Math.Min(PARCEL_MAX_ENTRIES_PER_PACKET, count - entryIndex)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < packet.List.Length; i++, entryIndex++)
|
||||||
|
{
|
||||||
|
var entry = entries[entryIndex];
|
||||||
|
packet.List[i] = new ParcelAccessListUpdatePacket.ListBlock
|
||||||
|
{
|
||||||
|
ID = entry.AgentID,
|
||||||
|
Time = (int)(entry.Time.Subtract(new DateTime(1970, 1, 1))).TotalSeconds,
|
||||||
|
Flags = (uint)entry.Flags
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no entries, send an empty block
|
||||||
|
if (packet.List.Length == 0)
|
||||||
|
{
|
||||||
|
packet.List = new ParcelAccessListUpdatePacket.ListBlock[1];
|
||||||
|
packet.List[0] = new ParcelAccessListUpdatePacket.ListBlock
|
||||||
|
{
|
||||||
|
ID = UUID.Zero,
|
||||||
|
Time = 0,
|
||||||
|
Flags = 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
simulator.SendPacket(packet);
|
||||||
|
sequenceId++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update the simulator with any local changes to this Parcel object
|
/// Update the simulator with any local changes to this Parcel object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2016, openmetaverse.co
|
* Copyright (c) 2006-2016, openmetaverse.co
|
||||||
|
* Copyright (c) 2025, Sjofn LLC.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* - Redistribution and use in source and binary forms, with or without
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
|
|
@ -58,7 +59,7 @@ namespace OpenMetaverse.Rendering
|
||||||
/// Load a skeleton from a given file.
|
/// Load a skeleton from a given file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// We use xml scema validation on top of the xml de-serializer, since the schema has
|
/// We use xml schema validation on top of the xml de-serializer, since the schema has
|
||||||
/// some stricter checks than the de-serializer provides. E.g. the vector attributes
|
/// some stricter checks than the de-serializer provides. E.g. the vector attributes
|
||||||
/// are guaranteed to hold only 3 float values. This reduces the need for error checking
|
/// are guaranteed to hold only 3 float values. This reduces the need for error checking
|
||||||
/// while working with the loaded skeleton.
|
/// while working with the loaded skeleton.
|
||||||
|
|
@ -68,7 +69,7 @@ namespace OpenMetaverse.Rendering
|
||||||
public static LindenSkeleton Load(string fileName)
|
public static LindenSkeleton Load(string fileName)
|
||||||
{
|
{
|
||||||
if (fileName == null)
|
if (fileName == null)
|
||||||
fileName = System.IO.Path.Combine(Settings.RESOURCE_DIR, "avatar_skeleton.xml");
|
fileName = System.IO.Path.Combine(Settings.RESOURCE_DIR, "character", "avatar_skeleton.xml");
|
||||||
|
|
||||||
LindenSkeleton result;
|
LindenSkeleton result;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2016, openmetaverse.co
|
* Copyright (c) 2006-2016, openmetaverse.co
|
||||||
* Copyright (c) 2021-2022, Sjofn LLC.
|
* Copyright (c) 2021-2025, Sjofn LLC.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* - Redistribution and use in source and binary forms, with or without
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
using OpenMetaverse.Packets;
|
using OpenMetaverse.Packets;
|
||||||
|
|
||||||
namespace OpenMetaverse
|
namespace OpenMetaverse
|
||||||
|
|
@ -49,7 +50,7 @@ namespace OpenMetaverse
|
||||||
public const string ADITI_LOGIN_SERVER = "https://login.aditi.lindenlab.com/cgi-bin/login.cgi";
|
public const string ADITI_LOGIN_SERVER = "https://login.aditi.lindenlab.com/cgi-bin/login.cgi";
|
||||||
|
|
||||||
/// <summary>The relative directory where external resources are kept</summary>
|
/// <summary>The relative directory where external resources are kept</summary>
|
||||||
public static string RESOURCE_DIR = "openmetaverse_data";
|
public static string RESOURCE_DIR = "linden";
|
||||||
|
|
||||||
/// <summary>Login server to connect to</summary>
|
/// <summary>Login server to connect to</summary>
|
||||||
public string LOGIN_SERVER = AGNI_LOGIN_SERVER;
|
public string LOGIN_SERVER = AGNI_LOGIN_SERVER;
|
||||||
|
|
@ -286,7 +287,7 @@ namespace OpenMetaverse
|
||||||
public bool USE_ASSET_CACHE = true;
|
public bool USE_ASSET_CACHE = true;
|
||||||
|
|
||||||
/// <summary>Path to store cached texture data</summary>
|
/// <summary>Path to store cached texture data</summary>
|
||||||
public string ASSET_CACHE_DIR = RESOURCE_DIR + "/cache";
|
public string ASSET_CACHE_DIR = Path.Combine(RESOURCE_DIR, "cache");
|
||||||
|
|
||||||
/// <summary>Maximum size cached files are allowed to take on disk (bytes)</summary>
|
/// <summary>Maximum size cached files are allowed to take on disk (bytes)</summary>
|
||||||
public long ASSET_CACHE_MAX_SIZE = 1024 * 1024 * 1024; // 1GB
|
public long ASSET_CACHE_MAX_SIZE = 1024 * 1024 * 1024; // 1GB
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using LibreMetaverse;
|
||||||
using OpenMetaverse.Packets;
|
using OpenMetaverse.Packets;
|
||||||
|
|
||||||
namespace OpenMetaverse
|
namespace OpenMetaverse
|
||||||
|
|
@ -263,6 +264,8 @@ namespace OpenMetaverse
|
||||||
public UUID ID = UUID.Zero;
|
public UUID ID = UUID.Zero;
|
||||||
/// <summary>The capabilities for this simulator</summary>
|
/// <summary>The capabilities for this simulator</summary>
|
||||||
public Caps Caps;
|
public Caps Caps;
|
||||||
|
/// <summary>Simulator Features available for this simulator</summary>
|
||||||
|
public SimulatorFeatures Features;
|
||||||
/// <summary>Unique identified for this region generated via it's coordinates on the world map</summary>
|
/// <summary>Unique identified for this region generated via it's coordinates on the world map</summary>
|
||||||
public ulong Handle;
|
public ulong Handle;
|
||||||
/// <summary>Simulator land size in X direction in meters</summary>
|
/// <summary>Simulator land size in X direction in meters</summary>
|
||||||
|
|
|
||||||
100
LibreMetaverse/SimulatorFeatures.cs
Normal file
100
LibreMetaverse/SimulatorFeatures.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Sjofn LLC.
|
||||||
|
* 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.
|
||||||
|
* - Neither the name of the openmetaverse.co 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 OWNER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenMetaverse.StructuredData;
|
||||||
|
|
||||||
|
namespace LibreMetaverse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Stores the Simulator Features provided by the SimulatorFeatures sim capability
|
||||||
|
/// </summary>
|
||||||
|
public class SimulatorFeatures
|
||||||
|
{
|
||||||
|
private OSDMap _featureMap = new OSDMap();
|
||||||
|
private readonly Simulator _simulator;
|
||||||
|
|
||||||
|
internal SimulatorFeatures(Simulator simulator)
|
||||||
|
{
|
||||||
|
_simulator = simulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if Simulator Features has a given feature and corresponding true value
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="feature"></param>
|
||||||
|
/// <returns>true if feature exists and is true</returns>
|
||||||
|
public bool Has(string feature)
|
||||||
|
{
|
||||||
|
return _featureMap.TryGetValue(feature, out var value) && value.AsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the value of a specified Simulator Feature
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="feature"></param>
|
||||||
|
/// <returns>Returns value of the specified Simulator Feature, null of not found.</returns>
|
||||||
|
public OSD Get(string feature)
|
||||||
|
{
|
||||||
|
return _featureMap.TryGetValue(feature, out var value) ? value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set SimulatorFeatures from <see cref="OSDMap"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response"></param>
|
||||||
|
/// <param name="responseData"></param>
|
||||||
|
/// <param name="error"></param>
|
||||||
|
/// <exception cref="ArgumentException">OSD type is not a map</exception>
|
||||||
|
public void SetFeatures(HttpResponseMessage response, byte[] responseData, Exception error)
|
||||||
|
{
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
Logger.Log($"Failed to retrieve simulator features. Error: {error.Message}",
|
||||||
|
Helpers.LogLevel.Warning, _simulator.Client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Logger.Log($"Failed to retrieve simulator features. Status: {response.StatusCode} {response.ReasonPhrase}",
|
||||||
|
Helpers.LogLevel.Warning, _simulator.Client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OSD features = OSDParser.Deserialize(responseData);
|
||||||
|
|
||||||
|
if (features.Type != OSDType.Map)
|
||||||
|
{
|
||||||
|
Logger.Log($"Simulator Features response was not valid LLSD map",
|
||||||
|
Helpers.LogLevel.Warning, _simulator.Client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_featureMap = (OSDMap)features;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
359
LibreMetaverse/linden/cc-by-sa-3.0.txt
Normal file
359
LibreMetaverse/linden/cc-by-sa-3.0.txt
Normal file
|
|
@ -0,0 +1,359 @@
|
||||||
|
Creative Commons Legal Code
|
||||||
|
|
||||||
|
Attribution-ShareAlike 3.0 Unported
|
||||||
|
|
||||||
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||||
|
LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
|
||||||
|
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||||
|
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||||
|
REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
|
||||||
|
DAMAGES RESULTING FROM ITS USE.
|
||||||
|
|
||||||
|
License
|
||||||
|
|
||||||
|
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
|
||||||
|
COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
|
||||||
|
COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
|
||||||
|
AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
|
||||||
|
|
||||||
|
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
|
||||||
|
TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
|
||||||
|
BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
|
||||||
|
CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
|
||||||
|
CONDITIONS.
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
a. "Adaptation" means a work based upon the Work, or upon the Work and
|
||||||
|
other pre-existing works, such as a translation, adaptation,
|
||||||
|
derivative work, arrangement of music or other alterations of a
|
||||||
|
literary or artistic work, or phonogram or performance and includes
|
||||||
|
cinematographic adaptations or any other form in which the Work may be
|
||||||
|
recast, transformed, or adapted including in any form recognizably
|
||||||
|
derived from the original, except that a work that constitutes a
|
||||||
|
Collection will not be considered an Adaptation for the purpose of
|
||||||
|
this License. For the avoidance of doubt, where the Work is a musical
|
||||||
|
work, performance or phonogram, the synchronization of the Work in
|
||||||
|
timed-relation with a moving image ("synching") will be considered an
|
||||||
|
Adaptation for the purpose of this License.
|
||||||
|
b. "Collection" means a collection of literary or artistic works, such as
|
||||||
|
encyclopedias and anthologies, or performances, phonograms or
|
||||||
|
broadcasts, or other works or subject matter other than works listed
|
||||||
|
in Section 1(f) below, which, by reason of the selection and
|
||||||
|
arrangement of their contents, constitute intellectual creations, in
|
||||||
|
which the Work is included in its entirety in unmodified form along
|
||||||
|
with one or more other contributions, each constituting separate and
|
||||||
|
independent works in themselves, which together are assembled into a
|
||||||
|
collective whole. A work that constitutes a Collection will not be
|
||||||
|
considered an Adaptation (as defined below) for the purposes of this
|
||||||
|
License.
|
||||||
|
c. "Creative Commons Compatible License" means a license that is listed
|
||||||
|
at https://creativecommons.org/compatiblelicenses that has been
|
||||||
|
approved by Creative Commons as being essentially equivalent to this
|
||||||
|
License, including, at a minimum, because that license: (i) contains
|
||||||
|
terms that have the same purpose, meaning and effect as the License
|
||||||
|
Elements of this License; and, (ii) explicitly permits the relicensing
|
||||||
|
of adaptations of works made available under that license under this
|
||||||
|
License or a Creative Commons jurisdiction license with the same
|
||||||
|
License Elements as this License.
|
||||||
|
d. "Distribute" means to make available to the public the original and
|
||||||
|
copies of the Work or Adaptation, as appropriate, through sale or
|
||||||
|
other transfer of ownership.
|
||||||
|
e. "License Elements" means the following high-level license attributes
|
||||||
|
as selected by Licensor and indicated in the title of this License:
|
||||||
|
Attribution, ShareAlike.
|
||||||
|
f. "Licensor" means the individual, individuals, entity or entities that
|
||||||
|
offer(s) the Work under the terms of this License.
|
||||||
|
g. "Original Author" means, in the case of a literary or artistic work,
|
||||||
|
the individual, individuals, entity or entities who created the Work
|
||||||
|
or if no individual or entity can be identified, the publisher; and in
|
||||||
|
addition (i) in the case of a performance the actors, singers,
|
||||||
|
musicians, dancers, and other persons who act, sing, deliver, declaim,
|
||||||
|
play in, interpret or otherwise perform literary or artistic works or
|
||||||
|
expressions of folklore; (ii) in the case of a phonogram the producer
|
||||||
|
being the person or legal entity who first fixes the sounds of a
|
||||||
|
performance or other sounds; and, (iii) in the case of broadcasts, the
|
||||||
|
organization that transmits the broadcast.
|
||||||
|
h. "Work" means the literary and/or artistic work offered under the terms
|
||||||
|
of this License including without limitation any production in the
|
||||||
|
literary, scientific and artistic domain, whatever may be the mode or
|
||||||
|
form of its expression including digital form, such as a book,
|
||||||
|
pamphlet and other writing; a lecture, address, sermon or other work
|
||||||
|
of the same nature; a dramatic or dramatico-musical work; a
|
||||||
|
choreographic work or entertainment in dumb show; a musical
|
||||||
|
composition with or without words; a cinematographic work to which are
|
||||||
|
assimilated works expressed by a process analogous to cinematography;
|
||||||
|
a work of drawing, painting, architecture, sculpture, engraving or
|
||||||
|
lithography; a photographic work to which are assimilated works
|
||||||
|
expressed by a process analogous to photography; a work of applied
|
||||||
|
art; an illustration, map, plan, sketch or three-dimensional work
|
||||||
|
relative to geography, topography, architecture or science; a
|
||||||
|
performance; a broadcast; a phonogram; a compilation of data to the
|
||||||
|
extent it is protected as a copyrightable work; or a work performed by
|
||||||
|
a variety or circus performer to the extent it is not otherwise
|
||||||
|
considered a literary or artistic work.
|
||||||
|
i. "You" means an individual or entity exercising rights under this
|
||||||
|
License who has not previously violated the terms of this License with
|
||||||
|
respect to the Work, or who has received express permission from the
|
||||||
|
Licensor to exercise rights under this License despite a previous
|
||||||
|
violation.
|
||||||
|
j. "Publicly Perform" means to perform public recitations of the Work and
|
||||||
|
to communicate to the public those public recitations, by any means or
|
||||||
|
process, including by wire or wireless means or public digital
|
||||||
|
performances; to make available to the public Works in such a way that
|
||||||
|
members of the public may access these Works from a place and at a
|
||||||
|
place individually chosen by them; to perform the Work to the public
|
||||||
|
by any means or process and the communication to the public of the
|
||||||
|
performances of the Work, including by public digital performance; to
|
||||||
|
broadcast and rebroadcast the Work by any means including signs,
|
||||||
|
sounds or images.
|
||||||
|
k. "Reproduce" means to make copies of the Work by any means including
|
||||||
|
without limitation by sound or visual recordings and the right of
|
||||||
|
fixation and reproducing fixations of the Work, including storage of a
|
||||||
|
protected performance or phonogram in digital form or other electronic
|
||||||
|
medium.
|
||||||
|
|
||||||
|
2. Fair Dealing Rights. Nothing in this License is intended to reduce,
|
||||||
|
limit, or restrict any uses free from copyright or rights arising from
|
||||||
|
limitations or exceptions that are provided for in connection with the
|
||||||
|
copyright protection under copyright law or other applicable laws.
|
||||||
|
|
||||||
|
3. License Grant. Subject to the terms and conditions of this License,
|
||||||
|
Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
|
||||||
|
perpetual (for the duration of the applicable copyright) license to
|
||||||
|
exercise the rights in the Work as stated below:
|
||||||
|
|
||||||
|
a. to Reproduce the Work, to incorporate the Work into one or more
|
||||||
|
Collections, and to Reproduce the Work as incorporated in the
|
||||||
|
Collections;
|
||||||
|
b. to create and Reproduce Adaptations provided that any such Adaptation,
|
||||||
|
including any translation in any medium, takes reasonable steps to
|
||||||
|
clearly label, demarcate or otherwise identify that changes were made
|
||||||
|
to the original Work. For example, a translation could be marked "The
|
||||||
|
original work was translated from English to Spanish," or a
|
||||||
|
modification could indicate "The original work has been modified.";
|
||||||
|
c. to Distribute and Publicly Perform the Work including as incorporated
|
||||||
|
in Collections; and,
|
||||||
|
d. to Distribute and Publicly Perform Adaptations.
|
||||||
|
e. For the avoidance of doubt:
|
||||||
|
|
||||||
|
i. Non-waivable Compulsory License Schemes. In those jurisdictions in
|
||||||
|
which the right to collect royalties through any statutory or
|
||||||
|
compulsory licensing scheme cannot be waived, the Licensor
|
||||||
|
reserves the exclusive right to collect such royalties for any
|
||||||
|
exercise by You of the rights granted under this License;
|
||||||
|
ii. Waivable Compulsory License Schemes. In those jurisdictions in
|
||||||
|
which the right to collect royalties through any statutory or
|
||||||
|
compulsory licensing scheme can be waived, the Licensor waives the
|
||||||
|
exclusive right to collect such royalties for any exercise by You
|
||||||
|
of the rights granted under this License; and,
|
||||||
|
iii. Voluntary License Schemes. The Licensor waives the right to
|
||||||
|
collect royalties, whether individually or, in the event that the
|
||||||
|
Licensor is a member of a collecting society that administers
|
||||||
|
voluntary licensing schemes, via that society, from any exercise
|
||||||
|
by You of the rights granted under this License.
|
||||||
|
|
||||||
|
The above rights may be exercised in all media and formats whether now
|
||||||
|
known or hereafter devised. The above rights include the right to make
|
||||||
|
such modifications as are technically necessary to exercise the rights in
|
||||||
|
other media and formats. Subject to Section 8(f), all rights not expressly
|
||||||
|
granted by Licensor are hereby reserved.
|
||||||
|
|
||||||
|
4. Restrictions. The license granted in Section 3 above is expressly made
|
||||||
|
subject to and limited by the following restrictions:
|
||||||
|
|
||||||
|
a. You may Distribute or Publicly Perform the Work only under the terms
|
||||||
|
of this License. You must include a copy of, or the Uniform Resource
|
||||||
|
Identifier (URI) for, this License with every copy of the Work You
|
||||||
|
Distribute or Publicly Perform. You may not offer or impose any terms
|
||||||
|
on the Work that restrict the terms of this License or the ability of
|
||||||
|
the recipient of the Work to exercise the rights granted to that
|
||||||
|
recipient under the terms of the License. You may not sublicense the
|
||||||
|
Work. You must keep intact all notices that refer to this License and
|
||||||
|
to the disclaimer of warranties with every copy of the Work You
|
||||||
|
Distribute or Publicly Perform. When You Distribute or Publicly
|
||||||
|
Perform the Work, You may not impose any effective technological
|
||||||
|
measures on the Work that restrict the ability of a recipient of the
|
||||||
|
Work from You to exercise the rights granted to that recipient under
|
||||||
|
the terms of the License. This Section 4(a) applies to the Work as
|
||||||
|
incorporated in a Collection, but this does not require the Collection
|
||||||
|
apart from the Work itself to be made subject to the terms of this
|
||||||
|
License. If You create a Collection, upon notice from any Licensor You
|
||||||
|
must, to the extent practicable, remove from the Collection any credit
|
||||||
|
as required by Section 4(c), as requested. If You create an
|
||||||
|
Adaptation, upon notice from any Licensor You must, to the extent
|
||||||
|
practicable, remove from the Adaptation any credit as required by
|
||||||
|
Section 4(c), as requested.
|
||||||
|
b. You may Distribute or Publicly Perform an Adaptation only under the
|
||||||
|
terms of: (i) this License; (ii) a later version of this License with
|
||||||
|
the same License Elements as this License; (iii) a Creative Commons
|
||||||
|
jurisdiction license (either this or a later license version) that
|
||||||
|
contains the same License Elements as this License (e.g.,
|
||||||
|
Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible
|
||||||
|
License. If you license the Adaptation under one of the licenses
|
||||||
|
mentioned in (iv), you must comply with the terms of that license. If
|
||||||
|
you license the Adaptation under the terms of any of the licenses
|
||||||
|
mentioned in (i), (ii) or (iii) (the "Applicable License"), you must
|
||||||
|
comply with the terms of the Applicable License generally and the
|
||||||
|
following provisions: (I) You must include a copy of, or the URI for,
|
||||||
|
the Applicable License with every copy of each Adaptation You
|
||||||
|
Distribute or Publicly Perform; (II) You may not offer or impose any
|
||||||
|
terms on the Adaptation that restrict the terms of the Applicable
|
||||||
|
License or the ability of the recipient of the Adaptation to exercise
|
||||||
|
the rights granted to that recipient under the terms of the Applicable
|
||||||
|
License; (III) You must keep intact all notices that refer to the
|
||||||
|
Applicable License and to the disclaimer of warranties with every copy
|
||||||
|
of the Work as included in the Adaptation You Distribute or Publicly
|
||||||
|
Perform; (IV) when You Distribute or Publicly Perform the Adaptation,
|
||||||
|
You may not impose any effective technological measures on the
|
||||||
|
Adaptation that restrict the ability of a recipient of the Adaptation
|
||||||
|
from You to exercise the rights granted to that recipient under the
|
||||||
|
terms of the Applicable License. This Section 4(b) applies to the
|
||||||
|
Adaptation as incorporated in a Collection, but this does not require
|
||||||
|
the Collection apart from the Adaptation itself to be made subject to
|
||||||
|
the terms of the Applicable License.
|
||||||
|
c. If You Distribute, or Publicly Perform the Work or any Adaptations or
|
||||||
|
Collections, You must, unless a request has been made pursuant to
|
||||||
|
Section 4(a), keep intact all copyright notices for the Work and
|
||||||
|
provide, reasonable to the medium or means You are utilizing: (i) the
|
||||||
|
name of the Original Author (or pseudonym, if applicable) if supplied,
|
||||||
|
and/or if the Original Author and/or Licensor designate another party
|
||||||
|
or parties (e.g., a sponsor institute, publishing entity, journal) for
|
||||||
|
attribution ("Attribution Parties") in Licensor's copyright notice,
|
||||||
|
terms of service or by other reasonable means, the name of such party
|
||||||
|
or parties; (ii) the title of the Work if supplied; (iii) to the
|
||||||
|
extent reasonably practicable, the URI, if any, that Licensor
|
||||||
|
specifies to be associated with the Work, unless such URI does not
|
||||||
|
refer to the copyright notice or licensing information for the Work;
|
||||||
|
and (iv) , consistent with Ssection 3(b), in the case of an
|
||||||
|
Adaptation, a credit identifying the use of the Work in the Adaptation
|
||||||
|
(e.g., "French translation of the Work by Original Author," or
|
||||||
|
"Screenplay based on original Work by Original Author"). The credit
|
||||||
|
required by this Section 4(c) may be implemented in any reasonable
|
||||||
|
manner; provided, however, that in the case of a Adaptation or
|
||||||
|
Collection, at a minimum such credit will appear, if a credit for all
|
||||||
|
contributing authors of the Adaptation or Collection appears, then as
|
||||||
|
part of these credits and in a manner at least as prominent as the
|
||||||
|
credits for the other contributing authors. For the avoidance of
|
||||||
|
doubt, You may only use the credit required by this Section for the
|
||||||
|
purpose of attribution in the manner set out above and, by exercising
|
||||||
|
Your rights under this License, You may not implicitly or explicitly
|
||||||
|
assert or imply any connection with, sponsorship or endorsement by the
|
||||||
|
Original Author, Licensor and/or Attribution Parties, as appropriate,
|
||||||
|
of You or Your use of the Work, without the separate, express prior
|
||||||
|
written permission of the Original Author, Licensor and/or Attribution
|
||||||
|
Parties.
|
||||||
|
d. Except as otherwise agreed in writing by the Licensor or as may be
|
||||||
|
otherwise permitted by applicable law, if You Reproduce, Distribute or
|
||||||
|
Publicly Perform the Work either by itself or as part of any
|
||||||
|
Adaptations or Collections, You must not distort, mutilate, modify or
|
||||||
|
take other derogatory action in relation to the Work which would be
|
||||||
|
prejudicial to the Original Author's honor or reputation. Licensor
|
||||||
|
agrees that in those jurisdictions (e.g. Japan), in which any exercise
|
||||||
|
of the right granted in Section 3(b) of this License (the right to
|
||||||
|
make Adaptations) would be deemed to be a distortion, mutilation,
|
||||||
|
modification or other derogatory action prejudicial to the Original
|
||||||
|
Author's honor and reputation, the Licensor will waive or not assert,
|
||||||
|
as appropriate, this Section, to the fullest extent permitted by the
|
||||||
|
applicable national law, to enable You to reasonably exercise Your
|
||||||
|
right under Section 3(b) of this License (right to make Adaptations)
|
||||||
|
but not otherwise.
|
||||||
|
|
||||||
|
5. Representations, Warranties and Disclaimer
|
||||||
|
|
||||||
|
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
|
||||||
|
OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
|
||||||
|
KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
|
||||||
|
INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
|
||||||
|
LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
|
||||||
|
WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
|
||||||
|
OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
|
||||||
|
LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
|
||||||
|
ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
|
||||||
|
ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
|
||||||
|
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
7. Termination
|
||||||
|
|
||||||
|
a. This License and the rights granted hereunder will terminate
|
||||||
|
automatically upon any breach by You of the terms of this License.
|
||||||
|
Individuals or entities who have received Adaptations or Collections
|
||||||
|
from You under this License, however, will not have their licenses
|
||||||
|
terminated provided such individuals or entities remain in full
|
||||||
|
compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
|
||||||
|
survive any termination of this License.
|
||||||
|
b. Subject to the above terms and conditions, the license granted here is
|
||||||
|
perpetual (for the duration of the applicable copyright in the Work).
|
||||||
|
Notwithstanding the above, Licensor reserves the right to release the
|
||||||
|
Work under different license terms or to stop distributing the Work at
|
||||||
|
any time; provided, however that any such election will not serve to
|
||||||
|
withdraw this License (or any other license that has been, or is
|
||||||
|
required to be, granted under the terms of this License), and this
|
||||||
|
License will continue in full force and effect unless terminated as
|
||||||
|
stated above.
|
||||||
|
|
||||||
|
8. Miscellaneous
|
||||||
|
|
||||||
|
a. Each time You Distribute or Publicly Perform the Work or a Collection,
|
||||||
|
the Licensor offers to the recipient a license to the Work on the same
|
||||||
|
terms and conditions as the license granted to You under this License.
|
||||||
|
b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
|
||||||
|
offers to the recipient a license to the original Work on the same
|
||||||
|
terms and conditions as the license granted to You under this License.
|
||||||
|
c. If any provision of this License is invalid or unenforceable under
|
||||||
|
applicable law, it shall not affect the validity or enforceability of
|
||||||
|
the remainder of the terms of this License, and without further action
|
||||||
|
by the parties to this agreement, such provision shall be reformed to
|
||||||
|
the minimum extent necessary to make such provision valid and
|
||||||
|
enforceable.
|
||||||
|
d. No term or provision of this License shall be deemed waived and no
|
||||||
|
breach consented to unless such waiver or consent shall be in writing
|
||||||
|
and signed by the party to be charged with such waiver or consent.
|
||||||
|
e. This License constitutes the entire agreement between the parties with
|
||||||
|
respect to the Work licensed here. There are no understandings,
|
||||||
|
agreements or representations with respect to the Work not specified
|
||||||
|
here. Licensor shall not be bound by any additional provisions that
|
||||||
|
may appear in any communication from You. This License may not be
|
||||||
|
modified without the mutual written agreement of the Licensor and You.
|
||||||
|
f. The rights granted under, and the subject matter referenced, in this
|
||||||
|
License were drafted utilizing the terminology of the Berne Convention
|
||||||
|
for the Protection of Literary and Artistic Works (as amended on
|
||||||
|
September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
|
||||||
|
Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
|
||||||
|
and the Universal Copyright Convention (as revised on July 24, 1971).
|
||||||
|
These rights and subject matter take effect in the relevant
|
||||||
|
jurisdiction in which the License terms are sought to be enforced
|
||||||
|
according to the corresponding provisions of the implementation of
|
||||||
|
those treaty provisions in the applicable national law. If the
|
||||||
|
standard suite of rights granted under applicable copyright law
|
||||||
|
includes additional rights not granted under this License, such
|
||||||
|
additional rights are deemed to be included in the License; this
|
||||||
|
License is not intended to restrict the license of any rights under
|
||||||
|
applicable law.
|
||||||
|
|
||||||
|
|
||||||
|
Creative Commons Notice
|
||||||
|
|
||||||
|
Creative Commons is not a party to this License, and makes no warranty
|
||||||
|
whatsoever in connection with the Work. Creative Commons will not be
|
||||||
|
liable to You or any party on any legal theory for any damages
|
||||||
|
whatsoever, including without limitation any general, special,
|
||||||
|
incidental or consequential damages arising in connection to this
|
||||||
|
license. Notwithstanding the foregoing two (2) sentences, if Creative
|
||||||
|
Commons has expressly identified itself as the Licensor hereunder, it
|
||||||
|
shall have all rights and obligations of Licensor.
|
||||||
|
|
||||||
|
Except for the limited purpose of indicating to the public that the
|
||||||
|
Work is licensed under the CCPL, Creative Commons does not authorize
|
||||||
|
the use by either party of the trademark "Creative Commons" or any
|
||||||
|
related trademark or logo of Creative Commons without the prior
|
||||||
|
written consent of Creative Commons. Any permitted use will be in
|
||||||
|
compliance with Creative Commons' then-current trademark usage
|
||||||
|
guidelines, as may be published on its website or otherwise made
|
||||||
|
available upon request from time to time. For the avoidance of doubt,
|
||||||
|
this trademark restriction does not form part of the License.
|
||||||
|
|
||||||
|
Creative Commons may be contacted at https://creativecommons.org/.
|
||||||
51
LibreMetaverse/linden/character/attentions.xml
Normal file
51
LibreMetaverse/linden/character/attentions.xml
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?xml version="1.0" encoding="US-ASCII" standalone="yes"?>
|
||||||
|
<!--
|
||||||
|
Default values for "Look At" controls.
|
||||||
|
Various events compete for avatar attention. I.E. control where the
|
||||||
|
user's avatar looks.
|
||||||
|
The avatar's head will turn to look towards the source of those events
|
||||||
|
as much as is possible.
|
||||||
|
If the head cannot turn due to an animation override, the eyes will still
|
||||||
|
track those events.
|
||||||
|
Avatar attention will be taken by events of equal of greater priorities
|
||||||
|
and will last for timeout number of seconds before reverting to idle.
|
||||||
|
Negative timeout values indicate attentions that never time out.
|
||||||
|
Avatar sex determines which set of attention settings are used.
|
||||||
|
Within each set, the following named attentions relate to the indicated events:
|
||||||
|
|
||||||
|
IDLE: Tracks the mouse pointer movement.
|
||||||
|
AUTO LISTEN: Tracks nearby chat.
|
||||||
|
FREELOOK: Tracks "target objects" and a case of mouse moved in 3rd person mode.
|
||||||
|
RESPOND: Tracks the beginning of typing.
|
||||||
|
HOVER: Tracks objects the mouse lingers over when "show hover tooltips" is on.
|
||||||
|
CONVERSATION: Tracks avatars and other objects clicked on.
|
||||||
|
SEOECT: Tracks objects grabbed and being moved.
|
||||||
|
FOCUS: Freezes during avatar customization and when focused on object or point.
|
||||||
|
MOUSELOOK: Tracks center of view when in mouselook view mode.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<linden_attentions version="1.0">
|
||||||
|
<gender name="Masculine">
|
||||||
|
<param attention="idle" priority="1.0" timeout="3.0" />
|
||||||
|
<param attention="auto_listen" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="freelook" priority="2.0" timeout="2.0" />
|
||||||
|
<param attention="respond" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="hover" priority="4.0" timeout="1.0" />
|
||||||
|
<param attention="conversation" priority="0.0" timeout="-1" />
|
||||||
|
<param attention="select" priority="6.0" timeout="-1" />
|
||||||
|
<param attention="focus" priority="6.0" timeout="-1" />
|
||||||
|
<param attention="mouselook" priority="7.0" timeout="-1" />
|
||||||
|
</gender>
|
||||||
|
<gender name="Feminine">
|
||||||
|
<param attention="idle" priority="1.0" timeout="3.0" />
|
||||||
|
<param attention="auto_listen" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="freelook" priority="2.0" timeout="2.0" />
|
||||||
|
<param attention="respond" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="hover" priority="4.0" timeout="1.0" />
|
||||||
|
<param attention="conversation" priority="0.0" timeout="-1" />
|
||||||
|
<param attention="select" priority="6.0" timeout="-1" />
|
||||||
|
<param attention="focus" priority="6.0" timeout="-1" />
|
||||||
|
<param attention="mouselook" priority="7.0" timeout="-1" />
|
||||||
|
</gender>
|
||||||
|
</linden_attentions>
|
||||||
|
|
||||||
51
LibreMetaverse/linden/character/attentionsN.xml
Normal file
51
LibreMetaverse/linden/character/attentionsN.xml
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?xml version="1.0" encoding="US-ASCII" standalone="yes"?>
|
||||||
|
<!--
|
||||||
|
Default values for "Look At" controls.
|
||||||
|
Various events compete for avatar attention. I.E. control where the
|
||||||
|
user's avatar looks.
|
||||||
|
The avatar's head will turn to look towards the source of those events
|
||||||
|
as much as is possible.
|
||||||
|
If the head cannot turn due to an animation override, the eyes will still
|
||||||
|
track those events.
|
||||||
|
Avatar attention will be taken by events of equal of greater priorities
|
||||||
|
and will last for timeout number of seconds before reverting to idle.
|
||||||
|
Negative timeout values indicate attentions that never time out.
|
||||||
|
Avatar sex determines which set of attention settings are used.
|
||||||
|
Within each set, the following named attentions relate to the indicated events:
|
||||||
|
|
||||||
|
IDLE: Tracks the mouse pointer movement.
|
||||||
|
AUTO LISTEN: Tracks nearby chat.
|
||||||
|
FREELOOK: Tracks "target objects" and a case of mouse moved in 3rd person mode.
|
||||||
|
RESPOND: Tracks the beginning of typing.
|
||||||
|
HOVER: Tracks objects the mouse lingers over when "show hover tooltips" is on.
|
||||||
|
CONVERSATION: Tracks avatars and other objects clicked on.
|
||||||
|
SEOECT: Tracks objects grabbed and being moved.
|
||||||
|
FOCUS: Freezes during avatar customization and when focused on object or point.
|
||||||
|
MOUSELOOK: Tracks center of view when in mouselook view mode.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<linden_attentions version="1.0">
|
||||||
|
<gender name="Masculine">
|
||||||
|
<param attention="idle" priority="1.0" timeout="3.0" />
|
||||||
|
<param attention="auto_listen" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="freelook" priority="2.0" timeout="2.0" />
|
||||||
|
<param attention="respond" priority="3.0" timeout="3.0" />
|
||||||
|
<param attention="hover" priority="4.0" timeout="1.0" />
|
||||||
|
<param attention="conversation" priority="5.0" timeout="3.0" />
|
||||||
|
<param attention="select" priority="3.5" timeout="-1" />
|
||||||
|
<param attention="focus" priority="3.5" timeout="20.0" />
|
||||||
|
<param attention="mouselook" priority="7.0" timeout="-1" />
|
||||||
|
</gender>
|
||||||
|
<gender name="Feminine">
|
||||||
|
<param attention="idle" priority="1.0" timeout="3.0" />
|
||||||
|
<param attention="auto_listen" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="freelook" priority="2.0" timeout="2.0" />
|
||||||
|
<param attention="respond" priority="3.0" timeout="6.0" />
|
||||||
|
<param attention="hover" priority="4.0" timeout="1.0" />
|
||||||
|
<param attention="conversation" priority="5.0" timeout="6.0" />
|
||||||
|
<param attention="select" priority="2.5" timeout="-1" />
|
||||||
|
<param attention="focus" priority="2.5" timeout="10.0" />
|
||||||
|
<param attention="mouselook" priority="7.0" timeout="-1" />
|
||||||
|
</gender>
|
||||||
|
</linden_attentions>
|
||||||
|
|
||||||
BIN
LibreMetaverse/linden/character/aux_base.tga
Normal file
BIN
LibreMetaverse/linden/character/aux_base.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_eye.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_eye.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_eye_1.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_eye_1.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_eyelashes.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_eyelashes.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_hair.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_hair.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_hair_1.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_hair_1.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_hair_2.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_hair_2.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_hair_3.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_hair_3.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_hair_4.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_hair_4.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_hair_5.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_hair_5.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_head.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_head.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_head_1.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_head_1.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_head_2.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_head_2.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_head_3.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_head_3.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_head_4.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_head_4.llm
Normal file
Binary file not shown.
17504
LibreMetaverse/linden/character/avatar_lad.xml
Normal file
17504
LibreMetaverse/linden/character/avatar_lad.xml
Normal file
File diff suppressed because it is too large
Load diff
BIN
LibreMetaverse/linden/character/avatar_lower_body.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_lower_body.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_lower_body_1.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_lower_body_1.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_lower_body_2.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_lower_body_2.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_lower_body_3.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_lower_body_3.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_lower_body_4.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_lower_body_4.llm
Normal file
Binary file not shown.
232
LibreMetaverse/linden/character/avatar_skeleton.xml
Normal file
232
LibreMetaverse/linden/character/avatar_skeleton.xml
Normal file
|
|
@ -0,0 +1,232 @@
|
||||||
|
<linden_skeleton num_bones="133" num_collision_volumes="26" version="2.0">
|
||||||
|
<bone aliases="hip avatar_mPelvis" connected="false" end="0.000 0.000 0.084" group="Torso" name="mPelvis" pivot="0.000000 0.000000 1.067015" pos="0.000 0.000 1.067" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true">
|
||||||
|
<collision_volume end="0.030 0.000 0.095" group="Collision" name="PELVIS" pos="-0.01 0 -0.02" rot="0.000000 8.00000 0.000000" scale="0.12 0.16 0.17" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="-0.100 0.000 0.000" group="Collision" name="BUTT" pos="-0.06 0 -0.1" rot="0.000000 0.00000 0.000000" scale="0.1 0.1 0.1" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mSpine1" connected="true" end="0.000 0.000 -0.084" group="Spine" name="mSpine1" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mSpine2" connected="true" end="0.000 0.000 0.084" group="Spine" name="mSpine2" pivot="0.000000 0.000000 -0.084073" pos="0.000 0.000 -0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="abdomen avatar_mTorso" connected="true" end="-0.015 0.000 0.205" group="Torso" name="mTorso" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.028 0.000 0.094" group="Collision" name="BELLY" pos="0.028 0 0.04" rot="0.000000 8.00000 0.000000" scale="0.09 0.13 0.15" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="0.000 0.100 0.000" group="Collision" name="LEFT_HANDLE" pos="0.0 0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="0.000 -0.100 0.000" group="Collision" name="RIGHT_HANDLE" pos="0.0 -0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="-0.100 0.000 0.000" group="Collision" name="LOWER_BACK" pos="0.0 0.0 0.023" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mSpine3" connected="true" end="0.015 0.000 -0.205" group="Spine" name="mSpine3" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mSpine4" connected="true" end="-0.015 0.000 0.205" group="Spine" name="mSpine4" pivot="0.015368 0.000000 -0.204877" pos="0.015 0.000 -0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="chest avatar_mChest" connected="true" end="-0.010 0.000 0.250" group="Torso" name="mChest" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="-0.096 0.000 0.152" group="Collision" name="CHEST" pos="0.028 0 0.07" rot="0.000000 -10.00000 0.000000" scale="0.11 0.15 0.2" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="0.080 0.000 -0.006" group="Collision" name="LEFT_PEC" pos="0.119 0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="0.080 0.000 -0.006" group="Collision" name="RIGHT_PEC" pos="0.119 -0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="-0.100 0.000 0.000" group="Collision" name="UPPER_BACK" pos="0.0 0.0 0.017" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15" support="base" reposition="true"/>
|
||||||
|
<bone aliases="neck avatar_mNeck" connected="true" end="0.000 0.000 0.077" group="Torso" name="mNeck" pivot="-0.009507 0.000000 0.251108" pos="-0.010 0.000 0.251" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 0.000 0.080" group="Collision" name="NECK" pos="0.0 0 0.02" rot="0.000000 0.000000 0.000000" scale="0.05 0.06 0.08" support="base"/>
|
||||||
|
<bone aliases="head avatar_mHead" connected="true" end="0.000 0.000 0.079" group="Torso" name="mHead" pivot="0.000000 -0.000000 0.075630" pos="0.000 -0.000 0.076" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 0.000 0.100" group="Collision" name="HEAD" pos="0.02 0 0.07" rot="0.000000 0.000000 0.000000" scale="0.11 0.09 0.12" support="base" reposition="true"/>
|
||||||
|
<bone aliases="figureHair avatar_mSkull" connected="false" end="0.000 0.000 0.033" group="Extra" name="mSkull" pivot="0.000000 0.000000 0.079000" pos="0.000 0.000 0.079" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mEyeRight" connected="false" end="0.025 0.000 0.000" group="Extra" name="mEyeRight" pivot="0.098466 -0.036000 0.079000" pos="0.098 -0.036 0.079" rot="0.000000 0.000000 -0.000000" scale="1.000 1.000 1.000" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mEyeLeft" connected="false" end="0.025 0.000 0.000" group="Extra" name="mEyeLeft" pivot="0.098461 0.036000 0.079000" pos="0.098 0.036 0.079" rot="0.000000 -0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceRoot" connected="false" end="0.020 0.000 0.000" group="Face" name="mFaceRoot" pivot="0.025000 0.000000 0.045000" pos="0.025 0.000 0.045" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mFaceEyeAltRight" connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltRight" pivot="0.073466 -0.036000 0.0339300" pos="0.073 -0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyeAltLeft" connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltLeft" pivot="0.073461 0.036000 0.0339300" pos="0.073 0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceForeheadLeft" connected="false" end="0.024 0.004 0.018" group="Face" name="mFaceForeheadLeft" pivot="0.061 0.035 0.083" pos="0.061 0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceForeheadRight" connected="false" end="0.024 -0.004 0.018" group="Face" name="mFaceForeheadRight" pivot="0.061 -0.035 0.083" pos="0.061 -0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowOuterLeft" connected="false" end="0.023 0.013 0.000" group="Eyes" name="mFaceEyebrowOuterLeft" pivot="0.064 0.051 0.048" pos="0.064 0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowCenterLeft" connected="false" end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterLeft" pivot="0.070 0.043 0.056" pos="0.070 0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowInnerLeft" connected="false" end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerLeft" pivot="0.075 0.022 0.051" pos="0.075 0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowOuterRight" connected="false" end="0.023 -0.013 0.000" group="Eyes" name="mFaceEyebrowOuterRight" pivot="0.064 -0.051 0.048" pos="0.064 -0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowCenterRight" connected="false" end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterRight" pivot="0.070 -0.043 0.056" pos="0.070 -0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowInnerRight" connected="false" end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerRight" pivot="0.075 -0.022 0.051" pos="0.075 -0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyeLidUpperLeft" connected="false" end="0.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyeLidLowerLeft" connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyeLidUpperRight" connected="false" end="0.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyeLidLowerRight" connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEar1Left" connected="false" end="-0.019 0.018 0.025" group="Ears" name="mFaceEar1Left" pivot="0.000 0.080 0.002" pos="0.000 0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mFaceEar2Left" connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Left" pivot="-0.019 0.018 0.025" pos="-0.019 0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mFaceEar1Right" connected="false" end="-0.019 -0.018 0.025" group="Ears" name="mFaceEar1Right" pivot="0.000 -0.080 0.002" pos="0.000 -0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mFaceEar2Right" connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Right" pivot="-0.019 -0.018 0.025" pos="-0.019 -0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mFaceNoseLeft" connected="false" end="0.015 0.004 0.000" group="Face" name="mFaceNoseLeft" pivot="0.086 0.015 -0.004" pos="0.086 0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceNoseCenter" connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceNoseCenter" pivot="0.102 0.000 0.000" pos="0.102 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceNoseRight" connected="false" end="0.015 -0.004 0.000" group="Face" name="mFaceNoseRight" pivot="0.086 -0.015 -0.004" pos="0.086 -0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceCheekLowerLeft" connected="false" end="0.013 0.030 0.000" group="Face" name="mFaceCheekLowerLeft" pivot="0.050 0.034 -0.031" pos="0.050 0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceCheekUpperLeft" connected="false" end="0.022 0.015 0.000" group="Face" name="mFaceCheekUpperLeft" pivot="0.070 0.034 -0.005" pos="0.070 0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceCheekLowerRight" connected="false" end="0.013 -0.030 0.000" group="Face" name="mFaceCheekLowerRight" pivot="0.050 -0.034 -0.031" pos="0.050 -0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceCheekUpperRight" connected="false" end="0.022 -0.015 0.000" group="Face" name="mFaceCheekUpperRight" pivot="0.070 -0.034 -0.005" pos="0.070 -0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceJaw" connected="false" end="0.059 0.000 -0.039" group="Mouth" name="mFaceJaw" pivot="-0.001 0.000 -0.015" pos="-0.001 0.000 -0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mFaceChin" connected="false" end="0.021 0.000 -0.018" group="Mouth" name="mFaceChin" pivot="0.074 0.000 -0.054" pos="0.074 0.000 -0.054" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceTeethLower" connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethLower" pivot="0.021 0.000 -0.039" pos="0.021 0.000 -0.039" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mFaceLipLowerLeft" connected="false" end="0.034 0.017 0.005" group="Lips" name="mFaceLipLowerLeft" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipLowerRight" connected="false" end="0.034 -0.017 0.005" group="Lips" name="mFaceLipLowerRight" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipLowerCenter" connected="false" end="0.040 0.000 0.002" group="Lips" name="mFaceLipLowerCenter" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceTongueBase" connected="false" end="0.022 0.000 0.007" group="Mouth" name="mFaceTongueBase" pivot="0.039 0.000 0.005" pos="0.039 0.000 0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mFaceTongueTip" connected="true" end="0.010 0.000 0.000" group="Mouth" name="mFaceTongueTip" pivot="0.022 0.000 0.007" pos="0.022 0.000 0.007" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mFaceJawShaper" connected="false" end="-0.017 0.000 0.000" group="Face" name="mFaceJawShaper" pivot="0.000 0.000 0.000" pos="0.000 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceForeheadCenter" connected="false" end="0.036 0.000 0.000" group="Face" name="mFaceForeheadCenter" pivot="0.069 0.000 0.065" pos="0.069 0.000 0.065" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceNoseBase" connected="false" end="0.014 0.000 0.000" group="Nose" name="mFaceNoseBase" pivot="0.094 0.000 -0.016" pos="0.094 0.000 -0.016" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceTeethUpper" connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethUpper" pivot="0.020 0.000 -0.030" pos="0.020 0.000 -0.030" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mFaceLipUpperLeft" connected="false" end="0.041 0.015 0.000" group="Lips" name="mFaceLipUpperLeft" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipUpperRight" connected="false" end="0.041 -0.015 0.000" group="Lips" name="mFaceLipUpperRight" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipCornerLeft" connected="false" end="0.045 0.051 0.000" group="Lips" name="mFaceLipCornerLeft" pivot="0.028 -0.019 -0.010" pos="0.028 -0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipCornerRight" connected="false" end="0.045 -0.051 0.000" group="Lips" name="mFaceLipCornerRight" pivot="0.028 0.019 -0.010" pos="0.028 0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipUpperCenter" connected="false" end="0.043 0.000 0.002" group="Lips" name="mFaceLipUpperCenter" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mFaceEyecornerInnerLeft" connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerLeft" pivot="0.075 0.017 0.032" pos="0.075 0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyecornerInnerRight" connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerRight" pivot="0.075 -0.017 0.032" pos="0.075 -0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceNoseBridge" connected="false" end="0.015 0.000 0.008" group="Nose" name="mFaceNoseBridge" pivot="0.091 0.000 0.020" pos="0.091 0.000 0.020" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="lCollar avatar_mCollarLeft" connected="false" end="0.000 0.079 0.000" group="Arms" name="mCollarLeft" pivot="-0.020927 0.084665 0.165396" pos="-0.021 0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 0.100 0.000" group="Collision" name="L_CLAVICLE" pos="0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="lShldr avatar_mShoulderLeft" connected="true" end="0.000 0.247 0.000" group="Arms" name="mShoulderLeft" pivot="0.000000 0.079000 -0.000000" pos="0.000 0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 0.130 -0.003" group="Collision" name="L_UPPER_ARM" pos="0.0 0.12 0.01" rot="-5.000000 0.00000 0.000000" scale="0.05 0.17 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="lForeArm avatar_mElbowLeft" connected="true" end="0.000 0.205 0.000" group="Arms" name="mElbowLeft" pivot="0.000000 0.248000 0.000000" pos="0.000 0.248 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 0.100 -0.001" group="Collision" name="L_LOWER_ARM" pos="0.0 0.1 0.0" rot="-3.000000 0.00000 0.000000" scale="0.04 0.14 0.04" support="base" reposition="true"/>
|
||||||
|
<bone aliases="lHand avatar_mWristLeft" connected="true" end="0.000 0.060 0.000" group="Arms" name="mWristLeft" pivot="-0.000000 0.204846 0.000000" pos="-0.000 0.205 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.005 0.049 -0.001" group="Collision" name="L_HAND" pos="0.01 0.05 0.0" rot="-3.000000 0.00000 -10.000000" scale="0.05 0.08 0.03" support="base"/>
|
||||||
|
<bone aliases="avatar_mHandMiddle1Left" connected="false" end="-0.001 0.040 -0.006" group="Hand" name="mHandMiddle1Left" pivot="0.013 0.101 0.015" pos="0.013 0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandMiddle2Left" connected="true" end="-0.001 0.049 -0.008" group="Hand" name="mHandMiddle2Left" pivot="-0.001 0.040 -0.006" pos="-0.001 0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandMiddle3Left" connected="true" end="-0.002 0.033 -0.006" group="Hand" name="mHandMiddle3Left" pivot="-0.001 0.049 -0.008" pos="-0.001 0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandIndex1Left" connected="false" end="0.017 0.036 -0.006" group="Hand" name="mHandIndex1Left" pivot="0.038 0.097 0.015" pos="0.038 0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandIndex2Left" connected="true" end="0.014 0.032 -0.006" group="Hand" name="mHandIndex2Left" pivot="0.017 0.036 -0.006" pos="0.017 0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandIndex3Left" connected="true" end="0.011 0.025 -0.004" group="Hand" name="mHandIndex3Left" pivot="0.014 0.032 -0.006" pos="0.014 0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandRing1Left" connected="false" end="-0.013 0.038 -0.008" group="Hand" name="mHandRing1Left" pivot="-0.010 0.099 0.009" pos="-0.010 0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandRing2Left" connected="true" end="-0.013 0.040 -0.009" group="Hand" name="mHandRing2Left" pivot="-0.013 0.038 -0.008" pos="-0.013 0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandRing3Left" connected="true" end="-0.010 0.028 -0.006" group="Hand" name="mHandRing3Left" pivot="-0.013 0.040 -0.009" pos="-0.013 0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandPinky1Left" connected="false" end="-0.024 0.025 -0.006" group="Hand" name="mHandPinky1Left" pivot="-0.031 0.095 0.003" pos="-0.031 0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandPinky2Left" connected="true" end="-0.015 0.018 -0.004" group="Hand" name="mHandPinky2Left" pivot="-0.024 0.025 -0.006" pos="-0.024 0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandPinky3Left" connected="true" end="-0.013 0.016 -0.004" group="Hand" name="mHandPinky3Left" pivot="-0.015 0.018 -0.004" pos="-0.015 0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandThumb1Left" connected="false" end="0.028 0.032 0.000" group="Hand" name="mHandThumb1Left" pivot="0.031 0.026 0.004" pos="0.031 0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandThumb2Left" connected="true" end="0.023 0.031 0.000" group="Hand" name="mHandThumb2Left" pivot="0.028 0.032 -0.001" pos="0.028 0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandThumb3Left" connected="true" end="0.015 0.025 0.000" group="Hand" name="mHandThumb3Left" pivot="0.023 0.031 -0.001" pos="0.023 0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="rCollar avatar_mCollarRight" connected="false" end="0.000 -0.079 0.000" group="Arms" name="mCollarRight" pivot="-0.020927 -0.085000 0.165396" pos="-0.021 -0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 -0.100 0.000" group="Collision" name="R_CLAVICLE" pos="0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="rShldr avatar_mShoulderRight" connected="true" end="0.000 -0.247 0.000" group="Arms" name="mShoulderRight" pivot="0.000000 -0.079418 -0.000000" pos="0.000 -0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 -0.130 -0.003" group="Collision" name="R_UPPER_ARM" pos="0.0 -0.12 0.01" rot="5.000000 0.00000 0.000000" scale="0.05 0.17 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="rForeArm avatar_mElbowRight" connected="true" end="0.000 -0.205 0.000" group="Arms" name="mElbowRight" pivot="0.000000 -0.248000 -0.000000" pos="0.000 -0.248 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 -0.100 -0.001" group="Collision" name="R_LOWER_ARM" pos="0.0 -0.1 0.0" rot="3.000000 0.00000 0.000000" scale="0.04 0.14 0.04" support="base" reposition="true"/>
|
||||||
|
<bone aliases="rHand avatar_mWristRight" connected="true" end="0.000 -0.060 0.000" group="Arms" name="mWristRight" pivot="-0.000000 -0.205000 -0.000000" pos="0.000 -0.205 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.005 -0.049 -0.001" group="Collision" name="R_HAND" pos="0.01 -0.05 0.0" rot="3.000000 0.00000 10.000000" scale="0.05 0.08 0.03" support="base"/>
|
||||||
|
<bone aliases="avatar_mHandMiddle1Right" connected="false" end="-0.001 -0.040 -0.006" group="Hand" name="mHandMiddle1Right" pivot="0.013 -0.101 0.015" pos="0.013 -0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandMiddle2Right" connected="true" end="-0.001 -0.049 -0.008" group="Hand" name="mHandMiddle2Right" pivot="-0.001 -0.040 -0.006" pos="-0.001 -0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandMiddle3Right" connected="true" end="-0.002 -0.033 -0.006" group="Hand" name="mHandMiddle3Right" pivot="-0.001 -0.049 -0.008" pos="-0.001 -0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandIndex1Right" connected="false" end="0.017 -0.036 -0.006" group="Hand" name="mHandIndex1Right" pivot="0.038 -0.097 0.015" pos="0.038 -0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandIndex2Right" connected="true" end="0.014 -0.032 -0.006" group="Hand" name="mHandIndex2Right" pivot="0.017 -0.036 -0.006" pos="0.017 -0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandIndex3Right" connected="true" end="0.011 -0.025 -0.004" group="Hand" name="mHandIndex3Right" pivot="0.014 -0.032 -0.006" pos="0.014 -0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandRing1Right" connected="false" end="-0.013 -0.038 -0.008" group="Hand" name="mHandRing1Right" pivot="-0.010 -0.099 0.009" pos="-0.010 -0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandRing2Right" connected="true" end="-0.013 -0.040 -0.009" group="Hand" name="mHandRing2Right" pivot="-0.013 -0.038 -0.008" pos="-0.013 -0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandRing3Right" connected="true" end="-0.010 -0.028 -0.006" group="Hand" name="mHandRing3Right" pivot="-0.013 -0.040 -0.009" pos="-0.013 -0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandPinky1Right" connected="false" end="-0.024 -0.025 -0.006" group="Hand" name="mHandPinky1Right" pivot="-0.031 -0.095 0.003" pos="-0.031 -0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandPinky2Right" connected="true" end="-0.015 -0.018 -0.004" group="Hand" name="mHandPinky2Right" pivot="-0.024 -0.025 -0.006" pos="-0.024 -0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandPinky3Right" connected="true" end="-0.013 -0.016 -0.004" group="Hand" name="mHandPinky3Right" pivot="-0.015 -0.018 -0.004" pos="-0.015 -0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandThumb1Right" connected="false" end="0.028 -0.032 0.000" group="Hand" name="mHandThumb1Right" pivot="0.031 -0.026 0.004" pos="0.031 -0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandThumb2Right" connected="true" end="0.023 -0.031 0.000" group="Hand" name="mHandThumb2Right" pivot="0.028 -0.032 -0.001" pos="0.028 -0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandThumb3Right" connected="true" end="0.015 -0.025 0.000" group="Hand" name="mHandThumb3Right" pivot="0.023 -0.031 -0.001" pos="0.023 -0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mWingsRoot" connected="false" end="-0.061 0.000 0.000" group="Wing" name="mWingsRoot" pivot="-0.014 0.000 0.000" pos="-0.014 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mWing1Left" connected="false" end="-0.168 0.169 0.067" group="Wing" name="mWing1Left" pivot="-0.099 0.105 0.181" pos="-0.099 0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing2Left" connected="true" end="-0.181 0.183 0.000" group="Wing" name="mWing2Left" pivot="-0.168 0.169 0.067" pos="-0.168 0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing3Left" connected="true" end="-0.171 0.173 0.000" group="Wing" name="mWing3Left" pivot="-0.181 0.183 0.000" pos="-0.181 0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing4Left" connected="true" end="-0.146 0.132 0.000" group="Wing" name="mWing4Left" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mWing4FanLeft" connected="true" end="-0.068 0.062 -0.159" group="Wing" name="mWing4FanLeft" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mWing1Right" connected="false" end="-0.168 -0.169 0.067" group="Wing" name="mWing1Right" pivot="-0.099 -0.105 0.181" pos="-0.099 -0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing2Right" connected="true" end="-0.181 -0.183 0.000" group="Wing" name="mWing2Right" pivot="-0.168 -0.169 0.067" pos="-0.168 -0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing3Right" connected="true" end="-0.171 -0.173 0.000" group="Wing" name="mWing3Right" pivot="-0.181 -0.183 0.000" pos="-0.181 -0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing4Right" connected="true" end="-0.146 -0.132 0.000" group="Wing" name="mWing4Right" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mWing4FanRight" connected="true" end="-0.068 -0.062 -0.159" group="Wing" name="mWing4FanRight" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="rThigh avatar_mHipRight" connected="false" end="-0.001 0.049 -0.491" group="Legs" name="mHipRight" pivot="0.033620 -0.128806 -0.041086" pos="0.034 -0.129 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true">
|
||||||
|
<collision_volume end="0.000 0.000 -0.200" group="Collision" name="R_UPPER_LEG" pos="-0.02 0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32" support="base" reposition="true"/>
|
||||||
|
<bone aliases="rShin avatar_mKneeRight" connected="true" end="-0.029 0.000 -0.469" group="Legs" name="mKneeRight" pivot="-0.000780 0.048635 -0.490922" pos="-0.001 0.049 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="-0.010 0.000 -0.150" group="Collision" name="R_LOWER_LEG" pos="-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25" support="base" reposition="true"/>
|
||||||
|
<bone aliases="rFoot avatar_mAnkleRight" connected="true" end="0.112 0.000 -0.061" group="Legs" name="mAnkleRight" pivot="-0.028869 0.000000 -0.468494" pos="-0.029 0.000 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.089 0.000 -0.026" group="Collision" name="R_FOOT" pos="0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFootRight" connected="true" end="0.105 -0.010 0.000" group="Extra" name="mFootRight" pivot="0.111956 -0.000000 -0.060637" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true">
|
||||||
|
<bone aliases="avatar_mToeRight" connected="false" end="0.020 0.000 0.000" group="Extra" name="mToeRight" pivot="0.105399 -0.010408 -0.000104" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="lThigh avatar_mHipLeft" connected="false" end="-0.001 -0.046 -0.491" group="Legs" name="mHipLeft" pivot="0.033757 0.126765 -0.040998" pos="0.034 0.127 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true">
|
||||||
|
<collision_volume end="0.000 0.000 -0.200" group="Collision" name="L_UPPER_LEG" pos="-0.02 -0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32" support="base" reposition="true"/>
|
||||||
|
<bone aliases="lShin avatar_mKneeLeft" connected="true" end="-0.029 0.001 -0.469" group="Legs" name="mKneeLeft" pivot="-0.000887 -0.045568 -0.491053" pos="-0.001 -0.046 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="-0.010 0.000 -0.150" group="Collision" name="L_LOWER_LEG" pos="-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25" support="base" reposition="true"/>
|
||||||
|
<bone aliases="lFoot avatar_mAnkleLeft" connected="true" end="0.112 0.000 -0.061" group="Legs" name="mAnkleLeft" pivot="-0.028887 0.001378 -0.468449" pos="-0.029 0.001 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.089 0.000 -0.026" group="Collision" name="L_FOOT" pos="0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFootLeft" connected="true" end="0.105 0.008 0.001" group="Extra" name="mFootLeft" pivot="0.111956 -0.000000 -0.060620" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true">
|
||||||
|
<bone aliases="avatar_mToeLeft" connected="false" end="0.020 0.000 0.000" group="Extra" name="mToeLeft" pivot="0.105387 0.008270 0.000871" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mTail1" connected="false" end="-0.197 0.000 0.000" group="Tail" name="mTail1" pivot="-0.116 0.000 0.047" pos="-0.116 0.000 0.047" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mTail2" connected="true" end="-0.168 0.000 0.000" group="Tail" name="mTail2" pivot="-0.197 0.000 0.000" pos="-0.197 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mTail3" connected="true" end="-0.142 0.000 0.000" group="Tail" name="mTail3" pivot="-0.168 0.000 0.000" pos="-0.168 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mTail4" connected="true" end="-0.112 0.000 0.000" group="Tail" name="mTail4" pivot="-0.142 0.000 0.000" pos="-0.142 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mTail5" connected="true" end="-0.094 0.000 0.000" group="Tail" name="mTail5" pivot="-0.112 0.000 0.000" pos="-0.112 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mTail6" connected="true" end="-0.089 0.000 0.000" group="Tail" name="mTail6" pivot="-0.094 0.000 0.000" pos="-0.094 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mGroin" connected="false" end="0.004 0.000 -0.066" group="Groin" name="mGroin" pivot="0.064 0.000 -0.097" pos="0.064 0.000 -0.097" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
<bone aliases="avatar_mHindLimbsRoot" connected="false" end="-0.204 0.000 0.000" group="Limb" name="mHindLimbsRoot" pivot="-0.200 0.000 0.084" pos="-0.200 0.000 0.084" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHindLimb1Left" connected="false" end="0.002 -0.046 -0.491" group="Limb" name="mHindLimb1Left" pivot="-0.204 0.129 -0.125" pos="-0.204 0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mHindLimb2Left" connected="true" end="-0.030 -0.003 -0.468" group="Limb" name="mHindLimb2Left" pivot="0.002 -0.046 -0.491" pos="0.002 -0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHindLimb3Left" connected="true" end="0.112 0.000 -0.061" group="Limb" name="mHindLimb3Left" pivot="-0.030 -0.003 -0.468" pos="-0.030 -0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHindLimb4Left" connected="true" end="0.105 0.008 0.000" group="Limb" name="mHindLimb4Left" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHindLimb1Right" connected="false" end="0.002 0.046 -0.491" group="Limb" name="mHindLimb1Right" pivot="-0.204 -0.129 -0.125" pos="-0.204 -0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mHindLimb2Right" connected="true" end="-0.030 0.003 -0.468" group="Limb" name="mHindLimb2Right" pivot="0.002 0.046 -0.491" pos="0.002 0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHindLimb3Right" connected="true" end="0.112 0.000 -0.061" group="Limb" name="mHindLimb3Right" pivot="-0.030 0.003 -0.468" pos="-0.030 0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHindLimb4Right" connected="true" end="0.105 -0.008 0.000" group="Limb" name="mHindLimb4Right" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</linden_skeleton>
|
||||||
BIN
LibreMetaverse/linden/character/avatar_skirt.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_skirt.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_skirt_1.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_skirt_1.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_skirt_2.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_skirt_2.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_skirt_3.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_skirt_3.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_skirt_4.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_skirt_4.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_upper_body.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_upper_body.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_upper_body_1.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_upper_body_1.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_upper_body_2.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_upper_body_2.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_upper_body_3.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_upper_body_3.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/avatar_upper_body_4.llm
Normal file
BIN
LibreMetaverse/linden/character/avatar_upper_body_4.llm
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/blush_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/blush_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/body_skingrain.tga
Normal file
BIN
LibreMetaverse/linden/character/body_skingrain.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/bodyfreckles_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/bodyfreckles_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/bump_face_wrinkles.tga
Normal file
BIN
LibreMetaverse/linden/character/bump_face_wrinkles.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/bump_head_base.tga
Normal file
BIN
LibreMetaverse/linden/character/bump_head_base.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/bump_lowerbody_base.tga
Normal file
BIN
LibreMetaverse/linden/character/bump_lowerbody_base.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/bump_pants_wrinkles.tga
Normal file
BIN
LibreMetaverse/linden/character/bump_pants_wrinkles.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/bump_shirt_wrinkles.tga
Normal file
BIN
LibreMetaverse/linden/character/bump_shirt_wrinkles.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/bump_upperbody_base.tga
Normal file
BIN
LibreMetaverse/linden/character/bump_upperbody_base.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/checkerboard.tga
Normal file
BIN
LibreMetaverse/linden/character/checkerboard.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/eyebrows_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/eyebrows_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/eyeliner_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/eyeliner_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/eyeshadow_inner_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/eyeshadow_inner_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/eyeshadow_outer_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/eyeshadow_outer_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/eyewhite.tga
Normal file
BIN
LibreMetaverse/linden/character/eyewhite.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/facehair_chincurtains_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/facehair_chincurtains_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/facehair_moustache_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/facehair_moustache_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/facehair_sideburns_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/facehair_sideburns_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/facehair_soulpatch_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/facehair_soulpatch_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/freckles_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/freckles_alpha.tga
Normal file
Binary file not shown.
7107
LibreMetaverse/linden/character/genepool.xml
Normal file
7107
LibreMetaverse/linden/character/genepool.xml
Normal file
File diff suppressed because it is too large
Load diff
BIN
LibreMetaverse/linden/character/glove_length_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/glove_length_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/gloves_fingers_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/gloves_fingers_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/head_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/head_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/head_color.tga
Normal file
BIN
LibreMetaverse/linden/character/head_color.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/head_hair.tga
Normal file
BIN
LibreMetaverse/linden/character/head_hair.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/head_highlights_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/head_highlights_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/head_shading_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/head_shading_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/head_skingrain.tga
Normal file
BIN
LibreMetaverse/linden/character/head_skingrain.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/invisible_head.tga
Normal file
BIN
LibreMetaverse/linden/character/invisible_head.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/jacket_length_lower_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/jacket_length_lower_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/jacket_length_upper_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/jacket_length_upper_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/jacket_open_lower_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/jacket_open_lower_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/jacket_open_upper_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/jacket_open_upper_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/lipgloss_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/lipgloss_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/lips_mask.tga
Normal file
BIN
LibreMetaverse/linden/character/lips_mask.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/lipstick_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/lipstick_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/lowerbody_color.tga
Normal file
BIN
LibreMetaverse/linden/character/lowerbody_color.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/lowerbody_highlights_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/lowerbody_highlights_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/lowerbody_shading_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/lowerbody_shading_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/nailpolish_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/nailpolish_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/pants_length_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/pants_length_alpha.tga
Normal file
Binary file not shown.
BIN
LibreMetaverse/linden/character/pants_waist_alpha.tga
Normal file
BIN
LibreMetaverse/linden/character/pants_waist_alpha.tga
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue