| 13 |
using OpenSim.Framework.Communications.Cache; |
using OpenSim.Framework.Communications.Cache; |
| 14 |
using OpenSim.Region.ClientStack; |
using OpenSim.Region.ClientStack; |
| 15 |
using OpenSim.Region.ClientStack.LindenUDP; |
using OpenSim.Region.ClientStack.LindenUDP; |
| 16 |
|
using ModularRex.RexNetwork.RexLogin; |
| 17 |
|
using System.Timers; |
| 18 |
|
using System.Text; |
| 19 |
|
|
| 20 |
namespace ModularRex.RexNetwork |
namespace ModularRex.RexNetwork |
| 21 |
{ |
{ |
| 26 |
/// In the case whereby functionality uses the same packets but differs |
/// In the case whereby functionality uses the same packets but differs |
| 27 |
/// between Rex and LL, you can use a override on those specific functions |
/// between Rex and LL, you can use a override on those specific functions |
| 28 |
/// to overload the request. |
/// to overload the request. |
| 29 |
|
/// |
| 30 |
|
/// This class acts as a base class for legacy client and new rex-ng client (Bob) |
| 31 |
/// </summary> |
/// </summary> |
| 32 |
public class RexClientView : LLClientView, IClientRexFaceExpression, IClientRexAppearance, IClientMediaURL, IRexClientCore |
public class RexClientViewBase : LLClientView, IClientRexFaceExpression, IClientRexAppearance, IClientMediaURL, IRexClientCore |
| 33 |
{ |
{ |
| 34 |
private static readonly ILog m_log = |
private static readonly ILog m_log = |
| 35 |
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
| 40 |
private string m_rexAvatarURL; |
private string m_rexAvatarURL; |
| 41 |
private string m_rexAvatarURLOverride; |
private string m_rexAvatarURLOverride; |
| 42 |
private string m_rexAuthURL; |
private string m_rexAuthURL; |
|
private string m_rexSkypeURL; |
|
| 43 |
|
|
| 44 |
private float m_RexCharacterSpeedMod = 1.0f; |
private float m_RexCharacterSpeedMod = 1.0f; |
| 45 |
private float m_RexVertMovementSpeedMod = 1.0f; |
private float m_RexVertMovementSpeedMod = 1.0f; |
|
private bool m_RexWalkDisabled = false; |
|
|
private bool m_RexFlyDisabled = false; |
|
| 46 |
|
|
| 47 |
public event RexAppearanceDelegate OnRexAppearance; |
public event RexAppearanceDelegate OnRexAppearance; |
| 48 |
public event RexGenericMessageDelegate OnRexFaceExpression; |
public event RexGenericMessageDelegate OnRexFaceExpression; |
| 53 |
public event ReceiveRexMediaURL OnReceiveRexMediaURL; |
public event ReceiveRexMediaURL OnReceiveRexMediaURL; |
| 54 |
public event RexGenericMessageDelegate OnPrimFreeData; |
public event RexGenericMessageDelegate OnPrimFreeData; |
| 55 |
|
|
| 56 |
public RexClientView(EndPoint remoteEP, IScene scene, IAssetCache assetCache, |
public RexClientViewBase(EndPoint remoteEP, IScene scene, |
| 57 |
LLPacketServer packServer, AuthenticateResponse authenSessions, UUID agentId, |
LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse authenSessions, UUID agentId, |
| 58 |
UUID sessionId, uint circuitCode, EndPoint proxyEP, ClientStackUserSettings userSettings) |
UUID sessionId, uint circuitCode) |
| 59 |
: base(remoteEP, scene, assetCache, packServer, authenSessions, agentId, |
: base(remoteEP, scene, udpServer, udpClient, authenSessions, agentId, |
| 60 |
sessionId, circuitCode, proxyEP, userSettings) |
sessionId, circuitCode) |
| 61 |
{ |
{ |
| 62 |
// Rex communication now occurs via GenericMessage |
// Rex communication now occurs via GenericMessage |
| 63 |
// We have a special handler here below. |
// We have a special handler here below. |
| 64 |
AddGenericPacketHandlers(); |
AddGenericPacketHandlers(); |
| 65 |
|
RegisterInterfaces(); |
|
OnBinaryGenericMessage += RexClientView_BinaryGenericMessage; |
|
|
OnGenericMessage += RealXtendClientView_OnGenericMessage; |
|
| 66 |
} |
} |
| 67 |
|
|
| 68 |
public RexClientView(EndPoint remoteEP, IScene scene, AssetCache assetCache, |
public RexClientViewBase(EndPoint remoteEP, IScene scene, |
| 69 |
LLPacketServer packServer, AuthenticateResponse authenSessions, UUID agentId, |
LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse authenSessions, UUID agentId, |
| 70 |
UUID sessionId, uint circuitCode, EndPoint proxyEP, string rexAvatarURL, string rexAuthURL, ClientStackUserSettings userSettings) |
UUID sessionId, uint circuitCode, string rexAvatarURL, string rexAuthURL) |
| 71 |
: base(remoteEP, scene, assetCache, packServer, authenSessions, agentId, |
: base(remoteEP, scene, udpServer, udpClient, authenSessions, agentId, |
| 72 |
sessionId, circuitCode, proxyEP, userSettings) |
sessionId, circuitCode) |
| 73 |
{ |
{ |
| 74 |
// Rex communication now occurs via GenericMessage |
// Rex communication now occurs via GenericMessage |
| 75 |
// We need to register GenericMessage handlers |
// We need to register GenericMessage handlers |
| 76 |
|
|
| 77 |
AddGenericPacketHandlers(); |
AddGenericPacketHandlers(); |
| 78 |
|
RegisterInterfaces(); |
|
OnBinaryGenericMessage += RexClientView_BinaryGenericMessage; |
|
| 79 |
|
|
| 80 |
RexAvatarURL = rexAvatarURL; |
RexAvatarURL = rexAvatarURL; |
| 81 |
RexAuthURL = rexAuthURL; |
RexAuthURL = rexAuthURL; |
| 83 |
|
|
| 84 |
private void AddGenericPacketHandlers() |
private void AddGenericPacketHandlers() |
| 85 |
{ |
{ |
| 86 |
|
OnBinaryGenericMessage += RexClientView_BinaryGenericMessage; |
| 87 |
|
OnGenericMessage += RealXtendClientView_OnGenericMessage; |
| 88 |
|
|
| 89 |
AddGenericPacketHandler("RexAppearance", RealXtendClientView_OnGenericMessage); |
AddGenericPacketHandler("RexAppearance", RealXtendClientView_OnGenericMessage); |
| 90 |
AddGenericPacketHandler("RexFaceExpression", RealXtendClientView_OnGenericMessage); |
AddGenericPacketHandler("RexFaceExpression", RealXtendClientView_OnGenericMessage); |
| 91 |
AddGenericPacketHandler("RexAvatarProp", RealXtendClientView_OnGenericMessage); |
AddGenericPacketHandler("RexAvatarProp", RealXtendClientView_OnGenericMessage); |
| 100 |
m_genericMessageHandlers.Add("rexfaceexpression", OnRexFaceExpression); |
m_genericMessageHandlers.Add("rexfaceexpression", OnRexFaceExpression); |
| 101 |
m_genericMessageHandlers.Add("rexavatarprop", OnRexAvatarProperties); |
m_genericMessageHandlers.Add("rexavatarprop", OnRexAvatarProperties); |
| 102 |
m_genericMessageHandlers.Add("rexmediaurl", TriggerOnReceivedRexMediaURL); |
m_genericMessageHandlers.Add("rexmediaurl", TriggerOnReceivedRexMediaURL); |
| 103 |
m_genericMessageHandlers.Add("rexdata", TriggerOnPrimFreeData); |
//m_genericMessageHandlers.Add("rexdata", TriggerOnPrimFreeData); |
| 104 |
} |
} |
| 105 |
|
|
| 106 |
|
/// <summary> |
| 107 |
|
/// Converts the Generic Message byte data to UTF8 string List and triggers the OnPrimFreeData |
| 108 |
|
/// </summary> |
| 109 |
|
/// <param name="sender">The sender.</param> |
| 110 |
|
/// <param name="method">The name of the method.</param> |
| 111 |
|
/// <param name="args">Generic message data in bytes</param> |
| 112 |
|
private void HandleRexPrimFreeData(object sender, string method, byte[][] args) |
| 113 |
|
{ |
| 114 |
|
//parse byte data to strings |
| 115 |
|
List<string> sargs = new List<string>(); |
| 116 |
|
|
| 117 |
|
foreach (byte[] arg in args) |
| 118 |
|
{ |
| 119 |
|
string s = FieldToUTF8String(arg); |
| 120 |
|
sargs.Add(s); |
| 121 |
|
} |
| 122 |
|
|
| 123 |
|
TriggerOnPrimFreeData(this, sargs); |
| 124 |
|
} |
| 125 |
|
|
| 126 |
|
/// <summary> |
| 127 |
|
/// Convert a variable length field (byte array) to a UTF8 string |
| 128 |
|
/// </summary> |
| 129 |
|
/// <param name="bytes">The byte array to convert to a string</param> |
| 130 |
|
/// <returns>A UTF8 string</returns> |
| 131 |
|
protected static string FieldToUTF8String(byte[] bytes) |
| 132 |
|
{ |
| 133 |
|
if (bytes.Length > 0 && bytes[bytes.Length - 1] == 0x00) |
| 134 |
|
return UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1); |
| 135 |
|
else |
| 136 |
|
return UTF8Encoding.UTF8.GetString(bytes); |
| 137 |
|
} |
| 138 |
|
|
| 139 |
/// <summary> |
/// <summary> |
| 140 |
/// Registers interfaces for IClientCore, |
/// Registers interfaces for IClientCore, |
| 141 |
/// every time you make a new Rex-specific |
/// every time you make a new Rex-specific |
| 142 |
/// Interface. Make sure to register it here. |
/// Interface. Make sure to register it here. |
| 143 |
/// </summary> |
/// </summary> |
| 144 |
protected override void RegisterInterfaces() |
protected void RegisterInterfaces() |
| 145 |
{ |
{ |
| 146 |
RegisterInterface<IClientRexAppearance>(this); |
RegisterInterface<IClientRexAppearance>(this); |
| 147 |
RegisterInterface<IClientRexFaceExpression>(this); |
RegisterInterface<IClientRexFaceExpression>(this); |
| 151 |
// Register our own class 'as-is' so it can be |
// Register our own class 'as-is' so it can be |
| 152 |
// used via IClientCore.Get<RexClientView>()... |
// used via IClientCore.Get<RexClientView>()... |
| 153 |
RegisterInterface(this); |
RegisterInterface(this); |
|
|
|
|
base.RegisterInterfaces(); |
|
| 154 |
} |
} |
| 155 |
|
|
| 156 |
#region Properties |
#region Properties |
| 207 |
} |
} |
| 208 |
} |
} |
| 209 |
|
|
|
|
|
|
/// <summary> |
|
|
/// Skype username of the avatar |
|
|
/// eg: Skypeuser |
|
|
/// </summary> |
|
|
public string RexSkypeURL |
|
|
{ |
|
|
get { return m_rexSkypeURL; } |
|
|
set { m_rexSkypeURL = value; } |
|
|
} |
|
|
|
|
| 210 |
/// <summary> |
/// <summary> |
| 211 |
/// The full Rex Username of this account |
/// The full Rex Username of this account |
| 212 |
/// Eg: user@hostname.com:10001 |
/// Eg: user@hostname.com:10001 |
| 242 |
set |
set |
| 243 |
{ |
{ |
| 244 |
m_rexAuthURL = value; |
m_rexAuthURL = value; |
|
|
|
|
// Request Agent Properties Asynchronously |
|
|
ThreadPool.QueueUserWorkItem(RequestProperties); |
|
| 245 |
} |
} |
| 246 |
} |
} |
| 247 |
|
|
| 257 |
set { m_RexVertMovementSpeedMod = value; } |
set { m_RexVertMovementSpeedMod = value; } |
| 258 |
} |
} |
| 259 |
|
|
|
public bool RexWalkDisabled |
|
|
{ |
|
|
get { return m_RexWalkDisabled; } |
|
|
set { m_RexWalkDisabled = value; } |
|
|
} |
|
|
|
|
|
public bool RexFlyDisabled |
|
|
{ |
|
|
get { return m_RexFlyDisabled; } |
|
|
set { m_RexFlyDisabled = value; } |
|
|
} |
|
|
|
|
| 260 |
#endregion |
#endregion |
| 261 |
|
|
| 262 |
|
|
| 263 |
private void RexClientView_BinaryGenericMessage(Object sender, string method, byte[][] args) |
protected void RexClientView_BinaryGenericMessage(Object sender, string method, byte[][] args) |
| 264 |
{ |
{ |
| 265 |
if(method == "RexPrimData".ToLower()) |
if(method == "RexPrimData".ToLower()) |
| 266 |
{ |
{ |
| 267 |
HandleRexPrimData(args); |
HandleRexPrimData(args); |
| 268 |
return; |
return; |
| 269 |
} |
} |
| 270 |
|
else if (method == "rexdata") |
| 271 |
|
{ |
| 272 |
|
HandleRexPrimFreeData(sender, method, args); |
| 273 |
|
return; |
| 274 |
|
} |
| 275 |
} |
} |
| 276 |
|
|
| 277 |
|
/// <summary> |
| 278 |
|
/// Handles the rex prim byte data, converts it to RexObjectProperties and triggers OnRexObjectProperties |
| 279 |
|
/// </summary> |
| 280 |
|
/// <param name="args">Rex prim data as bytes.</param> |
| 281 |
private void HandleRexPrimData(byte[][] args) |
private void HandleRexPrimData(byte[][] args) |
| 282 |
{ |
{ |
| 283 |
int rpdLen = 0; |
int rpdLen = 0; |
| 312 |
idx += arg.Length; |
idx += arg.Length; |
| 313 |
} |
} |
| 314 |
|
|
| 315 |
|
//by default message doesn't contain URIs. However, with NG-client situation can be quite different |
| 316 |
|
TriggerOnRexObjectProperties(this, id, new RexObjectProperties(rpdArray, false)); |
| 317 |
|
} |
| 318 |
|
|
| 319 |
|
protected void TriggerOnRexObjectProperties(RexClientViewBase client, UUID id, RexObjectProperties robject) |
| 320 |
|
{ |
| 321 |
if (OnRexObjectProperties != null) |
if (OnRexObjectProperties != null) |
| 322 |
OnRexObjectProperties(this, id, new RexObjectProperties(rpdArray)); |
{ |
| 323 |
|
OnRexObjectProperties(client, id, robject); |
| 324 |
|
} |
| 325 |
} |
} |
| 326 |
|
|
| 327 |
/// <summary> |
/// <summary> |
| 366 |
{ |
{ |
| 367 |
if (OnRexStartUp != null) |
if (OnRexStartUp != null) |
| 368 |
{ |
{ |
| 369 |
OnRexStartUp(this, AgentId, args[0]); |
OnRexStartUp(this, AgentId, args[1]); |
| 370 |
return; |
return; |
| 371 |
} |
} |
| 372 |
} |
} |
| 373 |
if (method == "rexprimdata") |
if (method == "rexprimdata") |
| 374 |
return; |
return; |
| 375 |
|
if (method == "rexdata") |
| 376 |
|
return; |
| 377 |
|
|
| 378 |
m_log.Warn("[REXCLIENT] Unhandled GenericMessage (" + method + ") {"); |
m_log.Warn("[REXCLIENT] Unhandled GenericMessage (" + method + ") {"); |
| 379 |
foreach (string s in args) |
foreach (string s in args) |
| 427 |
} |
} |
| 428 |
} |
} |
| 429 |
|
|
| 430 |
public void SendRexObjectProperties(UUID id, RexObjectProperties x) |
public virtual void SendRexObjectProperties(UUID id, RexObjectProperties x) |
| 431 |
{ |
{ |
| 432 |
GenericMessagePacket gmp = new GenericMessagePacket(); |
GenericMessagePacket gmp = new GenericMessagePacket(); |
| 433 |
gmp.MethodData.Method = Utils.StringToBytes("RexPrimData"); |
gmp.MethodData.Method = Utils.StringToBytes("RexPrimData"); |
| 434 |
|
|
| 435 |
byte[] temprexprimdata = x.GetRexPrimDataToBytes(); |
byte[] temprexprimdata = x.GetRexPrimDataToBytes(false); |
| 436 |
int numlines = 0; |
int numlines = 0; |
| 437 |
int i = 0; |
int i = 0; |
| 438 |
|
|
| 467 |
|
|
| 468 |
// m_log.Warn("[REXDEBUG]: SendRexPrimData " + vPrimId.ToString()); |
// m_log.Warn("[REXDEBUG]: SendRexPrimData " + vPrimId.ToString()); |
| 469 |
OutPacket(gmp, ThrottleOutPacketType.Task); |
OutPacket(gmp, ThrottleOutPacketType.Task); |
|
|
|
| 470 |
} |
} |
| 471 |
|
|
| 472 |
/// <summary> |
/// <summary> |
| 520 |
SendGenericMessage("RexFaceExpression", expressionData); |
SendGenericMessage("RexFaceExpression", expressionData); |
| 521 |
} |
} |
| 522 |
|
|
| 523 |
public void SendRexAppearance(UUID agentID, string avatarURL) |
public void SendRexAppearance(UUID agentID, string avatarURL, bool overrideUsed) |
| 524 |
{ |
{ |
| 525 |
List<string> pack = new List<string>(); |
List<string> pack = new List<string>(); |
| 526 |
pack.Add(avatarURL); |
pack.Add(avatarURL); |
| 527 |
pack.Add(agentID.ToString()); |
pack.Add(agentID.ToString()); |
| 528 |
|
pack.Add(overrideUsed.ToString()); |
| 529 |
|
|
| 530 |
SendGenericMessage("RexAppearance", pack); |
SendGenericMessage("RexAppearance", pack); |
| 531 |
} |
} |
| 532 |
|
|
| 533 |
/// <summary> |
/// <summary> |
|
/// Requests properties about this agent from their |
|
|
/// authentication server. This should be run in |
|
|
/// an async thread. |
|
|
/// |
|
|
/// Note that this particular function may set the |
|
|
/// avatars appearance which may in turn call |
|
|
/// additional modules and functions elsewhere. |
|
|
/// </summary> |
|
|
/// <param name="o"></param> |
|
|
private void RequestProperties(object o) |
|
|
{ |
|
|
m_log.Info("[REXCLIENT] Resolving avatar..."); |
|
|
Hashtable ReqVals = new Hashtable(); |
|
|
ReqVals["avatar_account"] = RexAccount; |
|
|
ReqVals["AuthenticationAddress"] = RexAuthURL; |
|
|
|
|
|
ArrayList SendParams = new ArrayList(); |
|
|
SendParams.Add(ReqVals); |
|
|
|
|
|
XmlRpcRequest req = new XmlRpcRequest("get_user_by_account", SendParams); |
|
|
|
|
|
m_log.Info("[REXCLIENT] Sending XMLRPC Request to http://" + RexAuthURL); |
|
|
|
|
|
XmlRpcResponse authreply = req.Send("http://" + RexAuthURL, 9000); |
|
|
|
|
|
//m_log.Info(authreply.ToString()); |
|
|
if (!((Hashtable)authreply.Value).ContainsKey("error_type")) |
|
|
{ |
|
|
string rexAsAddress = ((Hashtable)authreply.Value)["as_address"].ToString(); |
|
|
//string rexSkypeURL = ((Hashtable)authreply.Value)["skype_url"].ToString(); |
|
|
UUID userID = new UUID(((Hashtable) authreply.Value)["uuid"].ToString()); |
|
|
|
|
|
// Sanity check |
|
|
if (userID == AgentId) |
|
|
{ |
|
|
RexAvatarURL = rexAsAddress; |
|
|
//RexSkypeURL = rexSkypeURL; |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
m_log.Warn("[REXCLIENT]: User not found"); |
|
|
} |
|
|
} |
|
|
|
|
|
/// <summary> |
|
| 534 |
/// Sends Fog parameters to client. Only works underwater. |
/// Sends Fog parameters to client. Only works underwater. |
| 535 |
/// </summary> |
/// </summary> |
| 536 |
/// <param name="start">meters from camera where the fog starts</param> |
/// <param name="start">meters from camera where the fog starts</param> |
| 943 |
SendGenericMessage("RexCSEffect", pack); |
SendGenericMessage("RexCSEffect", pack); |
| 944 |
} |
} |
| 945 |
|
|
| 946 |
|
public void SendRexPrimFreeData(UUID primID, string rexData) |
| 947 |
|
{ |
| 948 |
|
List<string> pack = new List<string>(); |
| 949 |
|
|
| 950 |
|
int numlines = 0; |
| 951 |
|
int i = 0; |
| 952 |
|
//count number of lines. 200chars/line |
| 953 |
|
while (i <= rexData.Length) |
| 954 |
|
{ |
| 955 |
|
numlines++; |
| 956 |
|
i += 200; |
| 957 |
|
} |
| 958 |
|
|
| 959 |
|
pack.Add(primID.ToString()); |
| 960 |
|
|
| 961 |
|
string sline = ""; |
| 962 |
|
for (i = 0; i < numlines; i++) //cut the data to 200 char fields and add to packet |
| 963 |
|
{ |
| 964 |
|
if ((rexData.Length - i * 200) < 200) |
| 965 |
|
sline = rexData.Substring(i * 200, rexData.Length - i * 200); |
| 966 |
|
else |
| 967 |
|
sline = rexData.Substring(i * 200, 200); |
| 968 |
|
|
| 969 |
|
pack.Add(sline); |
| 970 |
|
} |
| 971 |
|
|
| 972 |
|
SendGenericMessage("RexData", pack); |
| 973 |
|
} |
| 974 |
|
|
| 975 |
public override void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint) |
public override void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint) |
| 976 |
{ |
{ |
| 977 |
|
IRexUDPPort module = m_scene.RequestModuleInterface<IRexUDPPort>(); |
| 978 |
|
if (module != null) |
| 979 |
|
{ |
| 980 |
|
int udpport = module.GetPort(neighbourHandle); |
| 981 |
|
|
| 982 |
m_log.DebugFormat("[REXCLIENT]: Informing Client About Neighbour {0}", neighbourExternalEndPoint); |
m_log.DebugFormat("[REXCLIENT]: Informing Client About Neighbour {0}", neighbourExternalEndPoint); |
| 983 |
base.InformClientOfNeighbour(neighbourHandle, new IPEndPoint(neighbourExternalEndPoint.Address, neighbourExternalEndPoint.Port-2000)); |
base.InformClientOfNeighbour(neighbourHandle, new IPEndPoint(neighbourExternalEndPoint.Address, udpport)); |
| 984 |
|
} |
| 985 |
|
else |
| 986 |
|
{ |
| 987 |
|
base.InformClientOfNeighbour(neighbourHandle, neighbourExternalEndPoint); |
| 988 |
|
} |
| 989 |
} |
} |
| 990 |
|
|
| 991 |
public override void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, IPEndPoint externalIPEndPoint, |
public override void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, IPEndPoint externalIPEndPoint, |
| 992 |
string capsURL) |
string capsURL) |
| 993 |
{ |
{ |
| 994 |
|
IRexUDPPort module = m_scene.RequestModuleInterface<IRexUDPPort>(); |
| 995 |
|
if (module != null) |
| 996 |
|
{ |
| 997 |
|
int udpport = module.GetPort(newRegionHandle); |
| 998 |
|
|
| 999 |
m_log.DebugFormat("[REXCLIENT]: Crossing client to region {0}", externalIPEndPoint); |
m_log.DebugFormat("[REXCLIENT]: Crossing client to region {0}", externalIPEndPoint); |
| 1000 |
base.CrossRegion(newRegionHandle, pos, lookAt, new IPEndPoint(externalIPEndPoint.Address, externalIPEndPoint.Port - 2000), capsURL); |
base.CrossRegion(newRegionHandle, pos, lookAt, new IPEndPoint(externalIPEndPoint.Address, udpport), capsURL); |
| 1001 |
|
} |
| 1002 |
|
else |
| 1003 |
|
{ |
| 1004 |
|
base.CrossRegion(newRegionHandle, pos, lookAt, externalIPEndPoint, capsURL); |
| 1005 |
|
} |
| 1006 |
} |
} |
| 1007 |
|
|
| 1008 |
public override void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint newRegionEndPoint, uint locationID, |
public override void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint newRegionEndPoint, uint locationID, |
| 1009 |
uint flags, string capsURL) |
uint flags, string capsURL) |
| 1010 |
{ |
{ |
| 1011 |
|
IRexUDPPort module = m_scene.RequestModuleInterface<IRexUDPPort>(); |
| 1012 |
|
if (module != null) |
| 1013 |
|
{ |
| 1014 |
|
int udpport = module.GetPort(regionHandle); |
| 1015 |
|
|
| 1016 |
m_log.DebugFormat("[REXCLIENT]: Sending region teleport to client {0}", newRegionEndPoint); |
m_log.DebugFormat("[REXCLIENT]: Sending region teleport to client {0}", newRegionEndPoint); |
| 1017 |
base.SendRegionTeleport(regionHandle, simAccess, new IPEndPoint(newRegionEndPoint.Address, newRegionEndPoint.Port - 2000), locationID, flags, capsURL); |
base.SendRegionTeleport(regionHandle, simAccess, new IPEndPoint(newRegionEndPoint.Address, udpport), locationID, flags, capsURL); |
| 1018 |
|
} |
| 1019 |
|
else |
| 1020 |
|
{ |
| 1021 |
|
base.SendRegionTeleport(regionHandle, simAccess, newRegionEndPoint, locationID, flags, capsURL); |
| 1022 |
|
} |
| 1023 |
} |
} |
| 1024 |
|
|
| 1025 |
|
#region Avatar terse update |
| 1026 |
|
|
| 1027 |
|
protected override void InitNewClient() |
| 1028 |
|
{ |
| 1029 |
|
m_avatarTerseUpdateTimer = new System.Timers.Timer(m_avatarTerseUpdateRate); |
| 1030 |
|
m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); |
| 1031 |
|
m_avatarTerseUpdateTimer.AutoReset = false; |
| 1032 |
|
|
| 1033 |
|
base.InitNewClient(); |
| 1034 |
|
} |
| 1035 |
|
|
| 1036 |
|
protected System.Timers.Timer m_avatarTerseUpdateTimer; |
| 1037 |
|
protected List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); |
| 1038 |
|
|
| 1039 |
|
/// <summary> |
| 1040 |
|
/// Send a terse positional/rotation/velocity update about an avatar |
| 1041 |
|
/// to the client. This avatar can be that of the client itself. |
| 1042 |
|
/// </summary> |
| 1043 |
|
public override void SendAvatarTerseUpdate(ulong regionHandle, |
| 1044 |
|
ushort timeDilation, uint localID, Vector3 position, |
| 1045 |
|
Vector3 velocity, Quaternion rotation, UUID agentid) |
| 1046 |
|
{ |
| 1047 |
|
if (rotation.X == rotation.Y && |
| 1048 |
|
rotation.Y == rotation.Z && |
| 1049 |
|
rotation.Z == rotation.W && rotation.W == 0) |
| 1050 |
|
rotation = Quaternion.Identity; |
| 1051 |
|
|
| 1052 |
|
position.Z = (float)(position.Z - 0.15); |
| 1053 |
|
|
| 1054 |
|
ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = |
| 1055 |
|
RexCreateAvatarImprovedBlock(localID, position, velocity, rotation); |
| 1056 |
|
//CreateAvatarImprovedBlock(localID, position, velocity, rotation); |
| 1057 |
|
|
| 1058 |
|
lock (m_avatarTerseUpdates) |
| 1059 |
|
{ |
| 1060 |
|
m_avatarTerseUpdates.Add(terseBlock); |
| 1061 |
|
|
| 1062 |
|
// If packet is full or own movement packet, send it. |
| 1063 |
|
if (m_avatarTerseUpdates.Count >= m_avatarTerseUpdatesPerPacket) |
| 1064 |
|
{ |
| 1065 |
|
ProcessAvatarTerseUpdates(this, null); |
| 1066 |
|
} |
| 1067 |
|
else if (m_avatarTerseUpdates.Count == 1) |
| 1068 |
|
{ |
| 1069 |
|
m_avatarTerseUpdateTimer.Start(); |
| 1070 |
|
} |
| 1071 |
|
} |
| 1072 |
|
} |
| 1073 |
|
|
| 1074 |
|
protected void ProcessAvatarTerseUpdates(object sender, ElapsedEventArgs e) |
| 1075 |
|
{ |
| 1076 |
|
lock (m_avatarTerseUpdates) |
| 1077 |
|
{ |
| 1078 |
|
ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); |
| 1079 |
|
|
| 1080 |
|
terse.RegionData = new ImprovedTerseObjectUpdatePacket.RegionDataBlock(); |
| 1081 |
|
|
| 1082 |
|
terse.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; |
| 1083 |
|
terse.RegionData.TimeDilation = |
| 1084 |
|
(ushort)(Scene.TimeDilation * ushort.MaxValue); |
| 1085 |
|
|
| 1086 |
|
int max = m_avatarTerseUpdatesPerPacket; |
| 1087 |
|
if (max > m_avatarTerseUpdates.Count) |
| 1088 |
|
max = m_avatarTerseUpdates.Count; |
| 1089 |
|
|
| 1090 |
|
int count = 0; |
| 1091 |
|
int size = 0; |
| 1092 |
|
|
| 1093 |
|
byte[] zerobuffer = new byte[1024]; |
| 1094 |
|
byte[] blockbuffer = new byte[1024]; |
| 1095 |
|
|
| 1096 |
|
for (count = 0; count < max; count++) |
| 1097 |
|
{ |
| 1098 |
|
int length = 0; |
| 1099 |
|
m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); |
| 1100 |
|
length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
| 1101 |
|
if (size + length > m_packetMTU) |
| 1102 |
|
break; |
| 1103 |
|
size += length; |
| 1104 |
|
} |
| 1105 |
|
|
| 1106 |
|
terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; |
| 1107 |
|
|
| 1108 |
|
for (int i = 0; i < count; i++) |
| 1109 |
|
{ |
| 1110 |
|
terse.ObjectData[i] = m_avatarTerseUpdates[0]; |
| 1111 |
|
m_avatarTerseUpdates.RemoveAt(0); |
| 1112 |
|
} |
| 1113 |
|
|
| 1114 |
|
terse.Header.Reliable = false; |
| 1115 |
|
terse.Header.Zerocoded = true; |
| 1116 |
|
OutPacket(terse, ThrottleOutPacketType.Task); |
| 1117 |
|
|
| 1118 |
|
if (m_avatarTerseUpdates.Count == 0) |
| 1119 |
|
m_avatarTerseUpdateTimer.Stop(); |
| 1120 |
|
} |
| 1121 |
|
} |
| 1122 |
|
|
| 1123 |
|
/// <summary> |
| 1124 |
|
/// Creates compressed avatar terse update block. This is about half smaller than the orginal SL |
| 1125 |
|
/// </summary> |
| 1126 |
|
/// <param name="localID"></param> |
| 1127 |
|
/// <param name="pos"></param> |
| 1128 |
|
/// <param name="velocity"></param> |
| 1129 |
|
/// <param name="rotation"></param> |
| 1130 |
|
/// <returns></returns> |
| 1131 |
|
protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock RexCreateAvatarImprovedBlock(uint localID, Vector3 pos, |
| 1132 |
|
Vector3 velocity, |
| 1133 |
|
Quaternion rotation) |
| 1134 |
|
{ |
| 1135 |
|
byte[] bytes = new byte[30]; |
| 1136 |
|
int i = 0; |
| 1137 |
|
ImprovedTerseObjectUpdatePacket.ObjectDataBlock dat = PacketPool.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); |
| 1138 |
|
|
| 1139 |
|
dat.TextureEntry = new byte[0]; |
| 1140 |
|
|
| 1141 |
|
uint ID = localID; |
| 1142 |
|
bytes[i++] = (byte)(ID % 256); |
| 1143 |
|
bytes[i++] = (byte)((ID >> 8) % 256); |
| 1144 |
|
bytes[i++] = (byte)((ID >> 16) % 256); |
| 1145 |
|
bytes[i++] = (byte)((ID >> 24) % 256); |
| 1146 |
|
|
| 1147 |
|
// pos |
| 1148 |
|
byte[] pb = pos.GetBytes(); |
| 1149 |
|
Array.Copy(pb, 0, bytes, i, pb.Length); |
| 1150 |
|
i += 12; |
| 1151 |
|
|
| 1152 |
|
// velocity |
| 1153 |
|
velocity = velocity / 128.0f; |
| 1154 |
|
velocity.X += 1; |
| 1155 |
|
velocity.Y += 1; |
| 1156 |
|
velocity.Z += 1; |
| 1157 |
|
|
| 1158 |
|
ushort InternVelocityX = (ushort)(32768 * velocity.X); |
| 1159 |
|
ushort InternVelocityY = (ushort)(32768 * velocity.Y); |
| 1160 |
|
ushort InternVelocityZ = (ushort)(32768 * velocity.Z); |
| 1161 |
|
bytes[i++] = (byte)(InternVelocityX % 256); |
| 1162 |
|
bytes[i++] = (byte)((InternVelocityX >> 8) % 256); |
| 1163 |
|
bytes[i++] = (byte)(InternVelocityY % 256); |
| 1164 |
|
bytes[i++] = (byte)((InternVelocityY >> 8) % 256); |
| 1165 |
|
bytes[i++] = (byte)(InternVelocityZ % 256); |
| 1166 |
|
bytes[i++] = (byte)((InternVelocityZ >> 8) % 256); |
| 1167 |
|
|
| 1168 |
|
//rotation |
| 1169 |
|
ushort rw = (ushort)(32768 * (rotation.W + 1)); |
| 1170 |
|
ushort rx = (ushort)(32768 * (rotation.X + 1)); |
| 1171 |
|
ushort ry = (ushort)(32768 * (rotation.Y + 1)); |
| 1172 |
|
ushort rz = (ushort)(32768 * (rotation.Z + 1)); |
| 1173 |
|
|
| 1174 |
|
//rot |
| 1175 |
|
bytes[i++] = (byte)(rx % 256); |
| 1176 |
|
bytes[i++] = (byte)((rx >> 8) % 256); |
| 1177 |
|
bytes[i++] = (byte)(ry % 256); |
| 1178 |
|
bytes[i++] = (byte)((ry >> 8) % 256); |
| 1179 |
|
bytes[i++] = (byte)(rz % 256); |
| 1180 |
|
bytes[i++] = (byte)((rz >> 8) % 256); |
| 1181 |
|
bytes[i++] = (byte)(rw % 256); |
| 1182 |
|
bytes[i++] = (byte)((rw >> 8) % 256); |
| 1183 |
|
|
| 1184 |
|
dat.Data = bytes; |
| 1185 |
|
return (dat); |
| 1186 |
|
} |
| 1187 |
|
#endregion |
| 1188 |
} |
} |
| 1189 |
} |
} |