| 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 |
|
|
| 19 |
namespace ModularRex.RexNetwork |
namespace ModularRex.RexNetwork |
| 20 |
{ |
{ |
| 222 |
set |
set |
| 223 |
{ |
{ |
| 224 |
m_rexAuthURL = value; |
m_rexAuthURL = value; |
|
|
|
|
// Request Agent Properties Asynchronously |
|
|
ThreadPool.QueueUserWorkItem(RequestProperties); |
|
| 225 |
} |
} |
| 226 |
} |
} |
| 227 |
|
|
| 492 |
} |
} |
| 493 |
|
|
| 494 |
/// <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> |
|
| 495 |
/// Sends Fog parameters to client. Only works underwater. |
/// Sends Fog parameters to client. Only works underwater. |
| 496 |
/// </summary> |
/// </summary> |
| 497 |
/// <param name="start">meters from camera where the fog starts</param> |
/// <param name="start">meters from camera where the fog starts</param> |
| 906 |
|
|
| 907 |
public override void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint) |
public override void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint) |
| 908 |
{ |
{ |
| 909 |
|
IRexUDPPort module = m_scene.RequestModuleInterface<IRexUDPPort>(); |
| 910 |
|
int udpport = module.GetPort(neighbourHandle); |
| 911 |
|
|
| 912 |
m_log.DebugFormat("[REXCLIENT]: Informing Client About Neighbour {0}", neighbourExternalEndPoint); |
m_log.DebugFormat("[REXCLIENT]: Informing Client About Neighbour {0}", neighbourExternalEndPoint); |
| 913 |
base.InformClientOfNeighbour(neighbourHandle, new IPEndPoint(neighbourExternalEndPoint.Address, neighbourExternalEndPoint.Port-2000)); |
base.InformClientOfNeighbour(neighbourHandle, new IPEndPoint(neighbourExternalEndPoint.Address, udpport)); |
| 914 |
} |
} |
| 915 |
|
|
| 916 |
public override void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, IPEndPoint externalIPEndPoint, |
public override void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, IPEndPoint externalIPEndPoint, |
| 917 |
string capsURL) |
string capsURL) |
| 918 |
{ |
{ |
| 919 |
|
IRexUDPPort module = m_scene.RequestModuleInterface<IRexUDPPort>(); |
| 920 |
|
int udpport = module.GetPort(newRegionHandle); |
| 921 |
|
|
| 922 |
m_log.DebugFormat("[REXCLIENT]: Crossing client to region {0}", externalIPEndPoint); |
m_log.DebugFormat("[REXCLIENT]: Crossing client to region {0}", externalIPEndPoint); |
| 923 |
base.CrossRegion(newRegionHandle, pos, lookAt, new IPEndPoint(externalIPEndPoint.Address, externalIPEndPoint.Port - 2000), capsURL); |
base.CrossRegion(newRegionHandle, pos, lookAt, new IPEndPoint(externalIPEndPoint.Address, udpport), capsURL); |
| 924 |
} |
} |
| 925 |
|
|
| 926 |
public override void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint newRegionEndPoint, uint locationID, |
public override void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint newRegionEndPoint, uint locationID, |
| 927 |
uint flags, string capsURL) |
uint flags, string capsURL) |
| 928 |
{ |
{ |
| 929 |
|
IRexUDPPort module = m_scene.RequestModuleInterface<IRexUDPPort>(); |
| 930 |
|
int udpport = module.GetPort(regionHandle); |
| 931 |
|
|
| 932 |
m_log.DebugFormat("[REXCLIENT]: Sending region teleport to client {0}", newRegionEndPoint); |
m_log.DebugFormat("[REXCLIENT]: Sending region teleport to client {0}", newRegionEndPoint); |
| 933 |
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); |
| 934 |
|
} |
| 935 |
|
|
| 936 |
|
#region Avatar terse update |
| 937 |
|
|
| 938 |
|
protected override void InitNewClient() |
| 939 |
|
{ |
| 940 |
|
m_avatarTerseUpdateTimer = new System.Timers.Timer(m_avatarTerseUpdateRate); |
| 941 |
|
m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); |
| 942 |
|
m_avatarTerseUpdateTimer.AutoReset = false; |
| 943 |
|
|
| 944 |
|
base.InitNewClient(); |
| 945 |
} |
} |
| 946 |
|
|
| 947 |
|
private System.Timers.Timer m_avatarTerseUpdateTimer; |
| 948 |
|
private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); |
| 949 |
|
|
| 950 |
|
/// <summary> |
| 951 |
|
/// Send a terse positional/rotation/velocity update about an avatar |
| 952 |
|
/// to the client. This avatar can be that of the client itself. |
| 953 |
|
/// </summary> |
| 954 |
|
public override void SendAvatarTerseUpdate(ulong regionHandle, |
| 955 |
|
ushort timeDilation, uint localID, Vector3 position, |
| 956 |
|
Vector3 velocity, Quaternion rotation, UUID agentid) |
| 957 |
|
{ |
| 958 |
|
if (rotation.X == rotation.Y && |
| 959 |
|
rotation.Y == rotation.Z && |
| 960 |
|
rotation.Z == rotation.W && rotation.W == 0) |
| 961 |
|
rotation = Quaternion.Identity; |
| 962 |
|
|
| 963 |
|
position.Z = (float)(position.Z - 0.15); |
| 964 |
|
|
| 965 |
|
ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = |
| 966 |
|
RexCreateAvatarImprovedBlock(localID, position, velocity, rotation); |
| 967 |
|
//CreateAvatarImprovedBlock(localID, position, velocity, rotation); |
| 968 |
|
|
| 969 |
|
lock (m_avatarTerseUpdates) |
| 970 |
|
{ |
| 971 |
|
m_avatarTerseUpdates.Add(terseBlock); |
| 972 |
|
|
| 973 |
|
// If packet is full or own movement packet, send it. |
| 974 |
|
if (m_avatarTerseUpdates.Count >= m_avatarTerseUpdatesPerPacket) |
| 975 |
|
{ |
| 976 |
|
ProcessAvatarTerseUpdates(this, null); |
| 977 |
|
} |
| 978 |
|
else if (m_avatarTerseUpdates.Count == 1) |
| 979 |
|
{ |
| 980 |
|
m_avatarTerseUpdateTimer.Start(); |
| 981 |
|
} |
| 982 |
|
} |
| 983 |
|
} |
| 984 |
|
|
| 985 |
|
private void ProcessAvatarTerseUpdates(object sender, ElapsedEventArgs e) |
| 986 |
|
{ |
| 987 |
|
lock (m_avatarTerseUpdates) |
| 988 |
|
{ |
| 989 |
|
ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); |
| 990 |
|
|
| 991 |
|
terse.RegionData = new ImprovedTerseObjectUpdatePacket.RegionDataBlock(); |
| 992 |
|
|
| 993 |
|
terse.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; |
| 994 |
|
terse.RegionData.TimeDilation = |
| 995 |
|
(ushort)(Scene.TimeDilation * ushort.MaxValue); |
| 996 |
|
|
| 997 |
|
int max = m_avatarTerseUpdatesPerPacket; |
| 998 |
|
if (max > m_avatarTerseUpdates.Count) |
| 999 |
|
max = m_avatarTerseUpdates.Count; |
| 1000 |
|
|
| 1001 |
|
int count = 0; |
| 1002 |
|
int size = 0; |
| 1003 |
|
|
| 1004 |
|
byte[] zerobuffer = new byte[1024]; |
| 1005 |
|
byte[] blockbuffer = new byte[1024]; |
| 1006 |
|
|
| 1007 |
|
for (count = 0; count < max; count++) |
| 1008 |
|
{ |
| 1009 |
|
int length = 0; |
| 1010 |
|
m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); |
| 1011 |
|
length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); |
| 1012 |
|
if (size + length > m_packetMTU) |
| 1013 |
|
break; |
| 1014 |
|
size += length; |
| 1015 |
|
} |
| 1016 |
|
|
| 1017 |
|
terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; |
| 1018 |
|
|
| 1019 |
|
for (int i = 0; i < count; i++) |
| 1020 |
|
{ |
| 1021 |
|
terse.ObjectData[i] = m_avatarTerseUpdates[0]; |
| 1022 |
|
m_avatarTerseUpdates.RemoveAt(0); |
| 1023 |
|
} |
| 1024 |
|
|
| 1025 |
|
terse.Header.Reliable = false; |
| 1026 |
|
terse.Header.Zerocoded = true; |
| 1027 |
|
OutPacket(terse, ThrottleOutPacketType.Task); |
| 1028 |
|
|
| 1029 |
|
if (m_avatarTerseUpdates.Count == 0) |
| 1030 |
|
m_avatarTerseUpdateTimer.Stop(); |
| 1031 |
|
} |
| 1032 |
|
} |
| 1033 |
|
|
| 1034 |
|
/// <summary> |
| 1035 |
|
/// Creates compressed avatar terse update block. This is about half smaller than the orginal SL |
| 1036 |
|
/// </summary> |
| 1037 |
|
/// <param name="localID"></param> |
| 1038 |
|
/// <param name="pos"></param> |
| 1039 |
|
/// <param name="velocity"></param> |
| 1040 |
|
/// <param name="rotation"></param> |
| 1041 |
|
/// <returns></returns> |
| 1042 |
|
protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock RexCreateAvatarImprovedBlock(uint localID, Vector3 pos, |
| 1043 |
|
Vector3 velocity, |
| 1044 |
|
Quaternion rotation) |
| 1045 |
|
{ |
| 1046 |
|
byte[] bytes = new byte[30]; |
| 1047 |
|
int i = 0; |
| 1048 |
|
ImprovedTerseObjectUpdatePacket.ObjectDataBlock dat = PacketPool.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); |
| 1049 |
|
|
| 1050 |
|
dat.TextureEntry = new byte[0]; |
| 1051 |
|
|
| 1052 |
|
uint ID = localID; |
| 1053 |
|
bytes[i++] = (byte)(ID % 256); |
| 1054 |
|
bytes[i++] = (byte)((ID >> 8) % 256); |
| 1055 |
|
bytes[i++] = (byte)((ID >> 16) % 256); |
| 1056 |
|
bytes[i++] = (byte)((ID >> 24) % 256); |
| 1057 |
|
|
| 1058 |
|
// pos |
| 1059 |
|
byte[] pb = pos.GetBytes(); |
| 1060 |
|
Array.Copy(pb, 0, bytes, i, pb.Length); |
| 1061 |
|
i += 12; |
| 1062 |
|
|
| 1063 |
|
// velocity |
| 1064 |
|
velocity = velocity / 128.0f; |
| 1065 |
|
velocity.X += 1; |
| 1066 |
|
velocity.Y += 1; |
| 1067 |
|
velocity.Z += 1; |
| 1068 |
|
|
| 1069 |
|
ushort InternVelocityX = (ushort)(32768 * velocity.X); |
| 1070 |
|
ushort InternVelocityY = (ushort)(32768 * velocity.Y); |
| 1071 |
|
ushort InternVelocityZ = (ushort)(32768 * velocity.Z); |
| 1072 |
|
bytes[i++] = (byte)(InternVelocityX % 256); |
| 1073 |
|
bytes[i++] = (byte)((InternVelocityX >> 8) % 256); |
| 1074 |
|
bytes[i++] = (byte)(InternVelocityY % 256); |
| 1075 |
|
bytes[i++] = (byte)((InternVelocityY >> 8) % 256); |
| 1076 |
|
bytes[i++] = (byte)(InternVelocityZ % 256); |
| 1077 |
|
bytes[i++] = (byte)((InternVelocityZ >> 8) % 256); |
| 1078 |
|
|
| 1079 |
|
//rotation |
| 1080 |
|
ushort rw = (ushort)(32768 * (rotation.W + 1)); |
| 1081 |
|
ushort rx = (ushort)(32768 * (rotation.X + 1)); |
| 1082 |
|
ushort ry = (ushort)(32768 * (rotation.Y + 1)); |
| 1083 |
|
ushort rz = (ushort)(32768 * (rotation.Z + 1)); |
| 1084 |
|
|
| 1085 |
|
//rot |
| 1086 |
|
bytes[i++] = (byte)(rx % 256); |
| 1087 |
|
bytes[i++] = (byte)((rx >> 8) % 256); |
| 1088 |
|
bytes[i++] = (byte)(ry % 256); |
| 1089 |
|
bytes[i++] = (byte)((ry >> 8) % 256); |
| 1090 |
|
bytes[i++] = (byte)(rz % 256); |
| 1091 |
|
bytes[i++] = (byte)((rz >> 8) % 256); |
| 1092 |
|
bytes[i++] = (byte)(rw % 256); |
| 1093 |
|
bytes[i++] = (byte)((rw >> 8) % 256); |
| 1094 |
|
|
| 1095 |
|
dat.Data = bytes; |
| 1096 |
|
return (dat); |
| 1097 |
|
} |
| 1098 |
|
#endregion |
| 1099 |
} |
} |
| 1100 |
} |
} |