diff --git a/libremetaverse-core/Libremetaverse/AgentManager.cs b/libremetaverse-core/Libremetaverse/AgentManager.cs
index 5c4e653..7db93f4 100644
--- a/libremetaverse-core/Libremetaverse/AgentManager.cs
+++ b/libremetaverse-core/Libremetaverse/AgentManager.cs
@@ -1561,6 +1561,8 @@ namespace OpenMetaverse
#region Chat and instant messages
+ protected int message_chunk_group_id = 0; // a int that starts at 1 goes upto 500 (then back to 1)
+
///
/// Send a text message from the Agent to the Simulator
///
@@ -1568,24 +1570,46 @@ namespace OpenMetaverse
/// The channel to send the message on, 0 is the public channel. Channels above 0
/// can be used however only scripts listening on the specified channel will see the message
/// Denotes the type of message being sent, shout, whisper, etc.
- public void Chat(string message, int channel, ChatType type)
+ /// Enables large messages to be split into chunks of 900 with [CHUNKGROUPID|CHUNKID|TOTALCHUNKS] at the start
+ /// Hides [CHUNKGROUPID|CHUNKID|TOTALCHUNKS] at the start of chunked messages
+ public void Chat(string message, int channel, ChatType type, bool allow_split_message = true, bool hide_chunk_grouping = true)
{
- ChatFromViewerPacket chat = new ChatFromViewerPacket
+ if ((message.Length > 900) && (allow_split_message == true))
{
- AgentData =
+ int group_id = message_chunk_group_id;
+ message_chunk_group_id++;
+ if (message_chunk_group_id > 500) message_chunk_group_id = 1;
+ string[] chunks = message.SplitBy(900).ToArray();
+ int chunkid = 1;
+ foreach (string C in chunks)
{
- AgentID = id,
- SessionID = Client.Self.SessionID
- },
- ChatData =
- {
- Channel = channel,
- Message = Utils.StringToBytes(message),
- Type = (byte) type
+ string chunk_grouping = "";
+ if (hide_chunk_grouping == false)
+ {
+ chunk_grouping = "[" + group_id.ToString() + "|" + chunkid.ToString() + "|" + chunks.Length.ToString() + "]";
+ }
+ Chat("" + chunk_grouping + "" + C + "", channel, type, false);
+ chunkid++;
}
- };
-
- Client.Network.SendPacket(chat);
+ }
+ else if ((message.Length > 0) && (message.Length < 1000))
+ {
+ ChatFromViewerPacket chat = new ChatFromViewerPacket
+ {
+ AgentData =
+ {
+ AgentID = id,
+ SessionID = Client.Self.SessionID
+ },
+ ChatData =
+ {
+ Channel = channel,
+ Message = Utils.StringToBytes(message),
+ Type = (byte) type
+ }
+ };
+ Client.Network.SendPacket(chat);
+ }
}
///
@@ -1676,31 +1700,38 @@ namespace OpenMetaverse
{
if (target != UUID.Zero)
{
- ImprovedInstantMessagePacket im = new ImprovedInstantMessagePacket();
+ string[] chunks = message.SplitBy(900).ToArray();
+ foreach (string C in chunks)
+ {
+ ImprovedInstantMessagePacket im = new ImprovedInstantMessagePacket();
- if (imSessionID.Equals(UUID.Zero) || imSessionID.Equals(AgentID))
- imSessionID = AgentID.Equals(target) ? AgentID : target ^ AgentID;
+ if (imSessionID.Equals(UUID.Zero) || imSessionID.Equals(AgentID))
+ imSessionID = AgentID.Equals(target) ? AgentID : target ^ AgentID;
- im.AgentData.AgentID = Client.Self.AgentID;
- im.AgentData.SessionID = Client.Self.SessionID;
+ im.AgentData.AgentID = Client.Self.AgentID;
+ im.AgentData.SessionID = Client.Self.SessionID;
- im.MessageBlock.Dialog = (byte)dialog;
- im.MessageBlock.FromAgentName = Utils.StringToBytes(fromName);
- im.MessageBlock.FromGroup = false;
- im.MessageBlock.ID = imSessionID;
- im.MessageBlock.Message = Utils.StringToBytes(message);
- im.MessageBlock.Offline = (byte)offline;
- im.MessageBlock.ToAgentID = target;
+ im.MessageBlock.Dialog = (byte)dialog;
+ im.MessageBlock.FromAgentName = Utils.StringToBytes(fromName);
+ im.MessageBlock.FromGroup = false;
+ im.MessageBlock.ID = imSessionID;
- im.MessageBlock.BinaryBucket = binaryBucket ?? Utils.EmptyBytes;
+ im.MessageBlock.Message = Utils.StringToBytes(C);
- // These fields are mandatory, even if we don't have valid values for them
- im.MessageBlock.Position = Vector3.Zero;
- //TODO: Allow region id to be correctly set by caller or fetched from Client.*
- im.MessageBlock.RegionID = regionID;
+ im.MessageBlock.Offline = (byte)offline;
+ im.MessageBlock.ToAgentID = target;
- // Send the message
- Client.Network.SendPacket(im);
+ im.MessageBlock.BinaryBucket = binaryBucket ?? Utils.EmptyBytes;
+
+ // These fields are mandatory, even if we don't have valid values for them
+ im.MessageBlock.Position = Vector3.Zero;
+ //TODO: Allow region id to be correctly set by caller or fetched from Client.*
+ im.MessageBlock.RegionID = regionID;
+
+ // Send the message
+ Client.Network.SendPacket(im);
+ Thread.Sleep(100);
+ }
}
else
{
@@ -1877,7 +1908,7 @@ namespace OpenMetaverse
CapsClient request = Client.Network.CurrentSim.Caps.CreateCapsClient("ChatSessionRequest");
if (request != null)
{
- ChatSessionAcceptInvitation acceptInvite = new ChatSessionAcceptInvitation {SessionID = session_id};
+ ChatSessionAcceptInvitation acceptInvite = new ChatSessionAcceptInvitation { SessionID = session_id };
request.BeginGetResponse(acceptInvite.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
lock (GroupChatSessions.Dictionary)
@@ -1957,7 +1988,7 @@ namespace OpenMetaverse
Color = new byte[4],
Duration = (type == PointAtType.Clear) ? 0.0f : Single.MaxValue / 4.0f,
ID = effectID,
- Type = (byte) EffectType.PointAt
+ Type = (byte)EffectType.PointAt
};
byte[] typeData = new byte[57];
@@ -2032,7 +2063,7 @@ namespace OpenMetaverse
Color = new byte[4],
Duration = duration,
ID = effectID,
- Type = (byte) EffectType.LookAt
+ Type = (byte)EffectType.LookAt
};
byte[] typeData = new byte[57];
@@ -2077,7 +2108,7 @@ namespace OpenMetaverse
Color = color.GetBytes(),
Duration = duration,
ID = effectID,
- Type = (byte) EffectType.Beam
+ Type = (byte)EffectType.Beam
};
byte[] typeData = new byte[56];
@@ -2117,7 +2148,7 @@ namespace OpenMetaverse
Color = color.GetBytes(),
Duration = duration,
ID = effectID,
- Type = (byte) EffectType.Sphere
+ Type = (byte)EffectType.Sphere
};
byte[] typeData = new byte[56];
@@ -2357,7 +2388,7 @@ namespace OpenMetaverse
///
public void Grab(uint objectLocalID)
{
- Grab(objectLocalID, Vector3.Zero, TOUCH_INVALID_TEXCOORD, TOUCH_INVALID_TEXCOORD,
+ Grab(objectLocalID, Vector3.Zero, TOUCH_INVALID_TEXCOORD, TOUCH_INVALID_TEXCOORD,
0, TOUCH_INVALID_VECTOR, TOUCH_INVALID_VECTOR, TOUCH_INVALID_VECTOR);
}
@@ -2373,7 +2404,7 @@ namespace OpenMetaverse
/// The surface normal of the position to grab (A normal is a vector perpendicular to the surface)
/// The surface bi-normal of the position to grab (A bi-normal is a vector tangent to the surface
/// pointing along the U direction of the tangent space
- public void Grab(uint objectLocalID, Vector3 grabOffset, Vector3 uvCoord, Vector3 stCoord,
+ public void Grab(uint objectLocalID, Vector3 grabOffset, Vector3 uvCoord, Vector3 stCoord,
int faceIndex, Vector3 position, Vector3 normal, Vector3 binormal)
{
ObjectGrabPacket grab = new ObjectGrabPacket
@@ -2411,7 +2442,7 @@ namespace OpenMetaverse
/// Drag target in region coordinates
public void GrabUpdate(UUID objectID, Vector3 grabPosition)
{
- GrabUpdate(objectID, grabPosition, Vector3.Zero, Vector3.Zero, Vector3.Zero,
+ GrabUpdate(objectID, grabPosition, Vector3.Zero, Vector3.Zero, Vector3.Zero,
0, Vector3.Zero, Vector3.Zero, Vector3.Zero);
}
@@ -2428,7 +2459,7 @@ namespace OpenMetaverse
/// The surface normal of the position to grab (A normal is a vector perpendicular to the surface)
/// The surface bi-normal of the position to grab (A bi-normal is a vector tangent to the surface
/// pointing along the U direction of the tangent space
- public void GrabUpdate(UUID objectID, Vector3 grabPosition, Vector3 grabOffset, Vector3 uvCoord, Vector3 stCoord,
+ public void GrabUpdate(UUID objectID, Vector3 grabPosition, Vector3 grabOffset, Vector3 uvCoord, Vector3 stCoord,
int faceIndex, Vector3 position, Vector3 normal, Vector3 binormal)
{
ObjectGrabUpdatePacket grab = new ObjectGrabUpdatePacket
@@ -2470,7 +2501,7 @@ namespace OpenMetaverse
///
public void DeGrab(uint objectLocalID)
{
- DeGrab(objectLocalID, TOUCH_INVALID_TEXCOORD, TOUCH_INVALID_TEXCOORD,
+ DeGrab(objectLocalID, TOUCH_INVALID_TEXCOORD, TOUCH_INVALID_TEXCOORD,
0, TOUCH_INVALID_VECTOR, TOUCH_INVALID_VECTOR, TOUCH_INVALID_VECTOR);
}
@@ -2485,7 +2516,7 @@ namespace OpenMetaverse
/// The surface normal of the position to grab (A normal is a vector perpendicular to the surface)
/// The surface bi-normal of the position to grab (A bi-normal is a vector tangent to the surface
/// pointing along the U direction of the tangent space
- public void DeGrab(uint objectLocalID, Vector3 uvCoord, Vector3 stCoord,
+ public void DeGrab(uint objectLocalID, Vector3 uvCoord, Vector3 stCoord,
int faceIndex, Vector3 position, Vector3 normal, Vector3 binormal)
{
ObjectDeGrabPacket degrab = new ObjectDeGrabPacket
@@ -2495,7 +2526,7 @@ namespace OpenMetaverse
AgentID = Client.Self.AgentID,
SessionID = Client.Self.SessionID
},
- ObjectData = {LocalID = objectLocalID},
+ ObjectData = { LocalID = objectLocalID },
SurfaceInfo = new ObjectDeGrabPacket.SurfaceInfoBlock[1]
};
@@ -2540,7 +2571,7 @@ namespace OpenMetaverse
AgentID = Client.Self.AgentID,
SessionID = Client.Self.SessionID
},
- MoneyData = {TransactionID = UUID.Zero}
+ MoneyData = { TransactionID = UUID.Zero }
};
Client.Network.SendPacket(money);
@@ -2678,11 +2709,11 @@ namespace OpenMetaverse
AutoResetEvent gotAsset = new AutoResetEvent(false);
Client.Assets.RequestAsset(gestureID, AssetType.Gesture, true,
- delegate(AssetDownload transfer, Asset asset)
+ delegate (AssetDownload transfer, Asset asset)
{
if (transfer.Success)
{
- gesture = (AssetGesture) asset;
+ gesture = (AssetGesture)asset;
}
gotAsset.Set();
@@ -2710,7 +2741,7 @@ namespace OpenMetaverse
switch (step.GestureStepType)
{
case GestureStepType.Chat:
- string text = ((GestureStepChat) step).Text;
+ string text = ((GestureStepChat)step).Text;
int channel = 0;
Match m;
@@ -2729,7 +2760,7 @@ namespace OpenMetaverse
break;
case GestureStepType.Animation:
- GestureStepAnimation anim = (GestureStepAnimation) step;
+ GestureStepAnimation anim = (GestureStepAnimation)step;
if (anim.AnimationStart)
{
@@ -2746,14 +2777,14 @@ namespace OpenMetaverse
break;
case GestureStepType.Sound:
- Client.Sound.PlaySound(((GestureStepSound) step).ID);
+ Client.Sound.PlaySound(((GestureStepSound)step).ID);
break;
case GestureStepType.Wait:
- GestureStepWait wait = (GestureStepWait) step;
+ GestureStepWait wait = (GestureStepWait)step;
if (wait.WaitForTime)
{
- Thread.Sleep((int) (1000f * wait.WaitTime));
+ Thread.Sleep((int)(1000f * wait.WaitTime));
}
if (wait.WaitForAnimation)
{
@@ -2838,7 +2869,7 @@ namespace OpenMetaverse
/// Whether to ensure delivery of this packet or not
public void AnimationStart(UUID animation, bool reliable)
{
- var animations = new Dictionary {[animation] = true};
+ var animations = new Dictionary { [animation] = true };
Animate(animations, reliable);
}
@@ -2851,7 +2882,7 @@ namespace OpenMetaverse
/// Whether to ensure delivery of this packet or not
public void AnimationStop(UUID animation, bool reliable)
{
- var animations = new Dictionary {[animation] = false};
+ var animations = new Dictionary { [animation] = false };
Animate(animations, reliable);
}
@@ -2866,7 +2897,7 @@ namespace OpenMetaverse
{
AgentAnimationPacket animate = new AgentAnimationPacket
{
- Header = {Reliable = reliable},
+ Header = { Reliable = reliable },
AgentData =
{
AgentID = Client.Self.AgentID,
@@ -3021,7 +3052,7 @@ namespace OpenMetaverse
// Wait a bit to see if the event queue comes online
AutoResetEvent queueEvent = new AutoResetEvent(false);
EventHandler queueCallback =
- delegate(object sender, EventQueueRunningEventArgs e)
+ delegate (object sender, EventQueueRunningEventArgs e)
{
if (e.Simulator == Client.Network.CurrentSim)
queueEvent.Set();
@@ -3137,7 +3168,7 @@ namespace OpenMetaverse
LureType = 0,
Message = Utils.StringToBytes(message)
},
- TargetData = new[] {new StartLurePacket.TargetDataBlock()}
+ TargetData = new[] { new StartLurePacket.TargetDataBlock() }
};
p.TargetData[0].TargetID = targetID;
Client.Network.SendPacket(p);
@@ -3272,7 +3303,7 @@ namespace OpenMetaverse
AgentID = Client.Self.AgentID,
SessionID = Client.Self.SessionID
},
- MuteData = {MuteCRC = 0}
+ MuteData = { MuteCRC = 0 }
};
Client.Network.SendPacket(mute);
@@ -3538,7 +3569,7 @@ namespace OpenMetaverse
AgentID = Client.Self.AgentID,
SessionID = Client.Self.sessionID
},
- Data = {PickID = pickID}
+ Data = { PickID = pickID }
};
Client.Network.SendPacket(delete);
@@ -3611,7 +3642,7 @@ namespace OpenMetaverse
AgentID = Client.Self.AgentID,
SessionID = Client.Self.SessionID
},
- Data = {ClassifiedID = classifiedID}
+ Data = { ClassifiedID = classifiedID }
};
Client.Network.SendPacket(classified);
@@ -3627,7 +3658,7 @@ namespace OpenMetaverse
{
CapsClient request = Client.Network.CurrentSim.Caps.CreateCapsClient("AttachmentResources");
- request.OnComplete += delegate(CapsClient client, OSD result, Exception error)
+ request.OnComplete += delegate (CapsClient client, OSD result, Exception error)
{
try
{
@@ -3673,7 +3704,7 @@ namespace OpenMetaverse
CapsClient request = Client.Network.CurrentSim.Caps.CreateCapsClient("SetDisplayName");
if (request == null)
{
- Logger.Log("Unable to obtain capability. Unable to set display name.",
+ Logger.Log("Unable to obtain capability. Unable to set display name.",
Helpers.LogLevel.Warning, Client);
return;
}
@@ -3742,7 +3773,7 @@ namespace OpenMetaverse
{
var map = ((OSDMap)result)["access_prefs"];
agentAccess = ((OSDMap)map)["max"];
- Logger.Log($"Max maturity access set to {agentAccess}", Helpers.LogLevel.Info, Client );
+ Logger.Log($"Max maturity access set to {agentAccess}", Helpers.LogLevel.Info, Client);
}
else if (error == null)
{
@@ -3753,7 +3784,7 @@ namespace OpenMetaverse
Logger.Log("Failed setting max maturity access.", Helpers.LogLevel.Warning, Client);
success = false;
}
-
+
if (callback != null)
{
try { callback(new AgentAccessEventArgs(success, agentAccess)); }
@@ -3762,7 +3793,7 @@ namespace OpenMetaverse
};
OSDMap req = new OSDMap();
- OSDMap prefs = new OSDMap {["max"] = access};
+ OSDMap prefs = new OSDMap { ["max"] = access };
req["access_prefs"] = prefs;
request.BeginGetResponse(req, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
@@ -3786,7 +3817,7 @@ namespace OpenMetaverse
{
var resultMap = result as OSDMap;
- if(error != null)
+ if (error != null)
{
Logger.Log($"Failed to set hover height: {error}.", Helpers.LogLevel.Warning, Client);
}
@@ -3801,7 +3832,8 @@ namespace OpenMetaverse
}
};
- var postData = new OSDMap {
+ var postData = new OSDMap
+ {
["hover_height"] = hoverHeight
};
request.BeginGetResponse(postData, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
@@ -4320,7 +4352,7 @@ namespace OpenMetaverse
if (m_AnimationsChanged != null)
{
- ThreadPool.QueueUserWorkItem(delegate(object o)
+ ThreadPool.QueueUserWorkItem(delegate (object o)
{ OnAnimationsChanged(new AnimationsChangedEventArgs(this.SignaledAnimations)); });
}
@@ -4510,7 +4542,7 @@ namespace OpenMetaverse
{
if (fndMbr.AvatarKey == UUID.Zero)
{
- fndMbr = new ChatSessionMember {AvatarKey = t.AgentID};
+ fndMbr = new ChatSessionMember { AvatarKey = t.AgentID };
lock (GroupChatSessions.Dictionary)
GroupChatSessions[msg.SessionID].Add(fndMbr);
@@ -4737,7 +4769,7 @@ namespace OpenMetaverse
{
MuteEntry me = new MuteEntry
{
- Type = (MuteType) int.Parse(m.Groups["MyteType"].Value),
+ Type = (MuteType)int.Parse(m.Groups["MyteType"].Value),
ID = new UUID(m.Groups["Key"].Value),
Name = m.Groups["Name"].Value
};
diff --git a/libremetaverse-core/Libremetaverse/Helpers.cs b/libremetaverse-core/Libremetaverse/Helpers.cs
index 86b88cf..b7b87ad 100644
--- a/libremetaverse-core/Libremetaverse/Helpers.cs
+++ b/libremetaverse-core/Libremetaverse/Helpers.cs
@@ -74,6 +74,21 @@ namespace OpenMetaverse
Debug
};
+
+ public static IEnumerable SplitBy(this string str, int chunkLength)
+ {
+ if (String.IsNullOrEmpty(str)) throw new ArgumentException();
+ if (chunkLength < 1) throw new ArgumentException();
+
+ for (int i = 0; i < str.Length; i += chunkLength)
+ {
+ if (chunkLength + i > str.Length)
+ chunkLength = str.Length - i;
+
+ yield return str.Substring(i, chunkLength);
+ }
+ }
+
///
///
///