diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 1113 |
1 files changed, 660 insertions, 453 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 5ee1596..849fec3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -84,6 +84,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
84 | public event ModifyTerrain OnModifyTerrain; | 84 | public event ModifyTerrain OnModifyTerrain; |
85 | public event Action<IClientAPI> OnRegionHandShakeReply; | 85 | public event Action<IClientAPI> OnRegionHandShakeReply; |
86 | public event GenericCall1 OnRequestWearables; | 86 | public event GenericCall1 OnRequestWearables; |
87 | public event CachedTextureRequest OnCachedTextureRequest; | ||
87 | public event SetAppearance OnSetAppearance; | 88 | public event SetAppearance OnSetAppearance; |
88 | public event AvatarNowWearing OnAvatarNowWearing; | 89 | public event AvatarNowWearing OnAvatarNowWearing; |
89 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; | 90 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; |
@@ -95,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
95 | public event Action<IClientAPI, bool> OnCompleteMovementToRegion; | 96 | public event Action<IClientAPI, bool> OnCompleteMovementToRegion; |
96 | public event UpdateAgent OnPreAgentUpdate; | 97 | public event UpdateAgent OnPreAgentUpdate; |
97 | public event UpdateAgent OnAgentUpdate; | 98 | public event UpdateAgent OnAgentUpdate; |
99 | public event UpdateAgent OnAgentCameraUpdate; | ||
98 | public event AgentRequestSit OnAgentRequestSit; | 100 | public event AgentRequestSit OnAgentRequestSit; |
99 | public event AgentSit OnAgentSit; | 101 | public event AgentSit OnAgentSit; |
100 | public event AvatarPickerRequest OnAvatarPickerRequest; | 102 | public event AvatarPickerRequest OnAvatarPickerRequest; |
@@ -335,6 +337,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
335 | private bool m_VelocityInterpolate = false; | 337 | private bool m_VelocityInterpolate = false; |
336 | private const uint MaxTransferBytesPerPacket = 600; | 338 | private const uint MaxTransferBytesPerPacket = 600; |
337 | 339 | ||
340 | private volatile bool m_justEditedTerrain = false; | ||
338 | 341 | ||
339 | /// <value> | 342 | /// <value> |
340 | /// List used in construction of data blocks for an object update packet. This is to stop us having to | 343 | /// List used in construction of data blocks for an object update packet. This is to stop us having to |
@@ -355,7 +358,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
355 | // protected HashSet<uint> m_attachmentsSent; | 358 | // protected HashSet<uint> m_attachmentsSent; |
356 | 359 | ||
357 | private bool m_deliverPackets = true; | 360 | private bool m_deliverPackets = true; |
358 | private int m_animationSequenceNumber = 1; | 361 | |
359 | private bool m_SendLogoutPacketWhenClosing = true; | 362 | private bool m_SendLogoutPacketWhenClosing = true; |
360 | 363 | ||
361 | /// <summary> | 364 | /// <summary> |
@@ -367,7 +370,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
367 | /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods | 370 | /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods |
368 | /// cannot retain a reference to it outside of that method. | 371 | /// cannot retain a reference to it outside of that method. |
369 | /// </remarks> | 372 | /// </remarks> |
370 | private AgentUpdateArgs m_lastAgentUpdateArgs; | 373 | private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs(); |
371 | 374 | ||
372 | protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); | 375 | protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); |
373 | protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers | 376 | protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers |
@@ -416,6 +419,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
416 | public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } } | 419 | public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } } |
417 | public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } | 420 | public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } |
418 | 421 | ||
422 | public int PingTimeMS | ||
423 | { | ||
424 | get | ||
425 | { | ||
426 | if (UDPClient != null) | ||
427 | return UDPClient.PingTimeMS; | ||
428 | return 0; | ||
429 | } | ||
430 | } | ||
431 | |||
419 | /// <summary> | 432 | /// <summary> |
420 | /// Entity update queues | 433 | /// Entity update queues |
421 | /// </summary> | 434 | /// </summary> |
@@ -437,7 +450,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
437 | public string Name { get { return FirstName + " " + LastName; } } | 450 | public string Name { get { return FirstName + " " + LastName; } } |
438 | 451 | ||
439 | public uint CircuitCode { get { return m_circuitCode; } } | 452 | public uint CircuitCode { get { return m_circuitCode; } } |
440 | public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } | 453 | public int NextAnimationSequenceNumber |
454 | { | ||
455 | get { return m_udpServer.NextAnimationSequenceNumber; } | ||
456 | } | ||
441 | 457 | ||
442 | /// <summary> | 458 | /// <summary> |
443 | /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to | 459 | /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to |
@@ -458,6 +474,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
458 | set { m_disableFacelights = value; } | 474 | set { m_disableFacelights = value; } |
459 | } | 475 | } |
460 | 476 | ||
477 | |||
461 | public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } | 478 | public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } |
462 | 479 | ||
463 | 480 | ||
@@ -504,6 +521,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
504 | m_udpServer = udpServer; | 521 | m_udpServer = udpServer; |
505 | m_udpClient = udpClient; | 522 | m_udpClient = udpClient; |
506 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; | 523 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; |
524 | m_udpClient.HasUpdates += HandleHasUpdates; | ||
507 | m_udpClient.OnPacketStats += PopulateStats; | 525 | m_udpClient.OnPacketStats += PopulateStats; |
508 | 526 | ||
509 | m_prioritizer = new Prioritizer(m_scene); | 527 | m_prioritizer = new Prioritizer(m_scene); |
@@ -533,7 +551,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
533 | // We still perform a force close inside the sync lock since this is intended to attempt close where | 551 | // We still perform a force close inside the sync lock since this is intended to attempt close where |
534 | // there is some unidentified connection problem, not where we have issues due to deadlock | 552 | // there is some unidentified connection problem, not where we have issues due to deadlock |
535 | if (!IsActive && !force) | 553 | if (!IsActive && !force) |
554 | { | ||
555 | m_log.DebugFormat( | ||
556 | "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set", | ||
557 | Name, m_scene.Name); | ||
558 | |||
536 | return; | 559 | return; |
560 | } | ||
537 | 561 | ||
538 | IsActive = false; | 562 | IsActive = false; |
539 | CloseWithoutChecks(sendStop); | 563 | CloseWithoutChecks(sendStop); |
@@ -583,7 +607,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
583 | 607 | ||
584 | // Disable UDP handling for this client | 608 | // Disable UDP handling for this client |
585 | m_udpClient.Shutdown(); | 609 | m_udpClient.Shutdown(); |
586 | 610 | ||
587 | 611 | ||
588 | //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); | 612 | //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); |
589 | //GC.Collect(); | 613 | //GC.Collect(); |
@@ -709,12 +733,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
709 | //there is a local handler for this packet type | 733 | //there is a local handler for this packet type |
710 | if (pprocessor.Async) | 734 | if (pprocessor.Async) |
711 | { | 735 | { |
736 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
737 | if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString())) | ||
738 | cinfo.AsyncRequests[packet.Type.ToString()] = 0; | ||
739 | cinfo.AsyncRequests[packet.Type.ToString()]++; | ||
740 | |||
712 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); | 741 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); |
713 | Util.FireAndForget(ProcessSpecificPacketAsync, obj); | 742 | Util.FireAndForget(ProcessSpecificPacketAsync, obj); |
714 | result = true; | 743 | result = true; |
715 | } | 744 | } |
716 | else | 745 | else |
717 | { | 746 | { |
747 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
748 | if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString())) | ||
749 | cinfo.SyncRequests[packet.Type.ToString()] = 0; | ||
750 | cinfo.SyncRequests[packet.Type.ToString()]++; | ||
751 | |||
718 | result = pprocessor.method(this, packet); | 752 | result = pprocessor.method(this, packet); |
719 | } | 753 | } |
720 | } | 754 | } |
@@ -729,6 +763,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
729 | } | 763 | } |
730 | if (found) | 764 | if (found) |
731 | { | 765 | { |
766 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
767 | if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString())) | ||
768 | cinfo.GenericRequests[packet.Type.ToString()] = 0; | ||
769 | cinfo.GenericRequests[packet.Type.ToString()]++; | ||
770 | |||
732 | result = method(this, packet); | 771 | result = method(this, packet); |
733 | } | 772 | } |
734 | } | 773 | } |
@@ -758,7 +797,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
758 | 797 | ||
759 | public virtual void Start() | 798 | public virtual void Start() |
760 | { | 799 | { |
761 | m_scene.AddNewClient(this, PresenceType.User); | 800 | m_scene.AddNewAgent(this, PresenceType.User); |
762 | 801 | ||
763 | RefreshGroupMembership(); | 802 | RefreshGroupMembership(); |
764 | } | 803 | } |
@@ -820,14 +859,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
820 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); | 859 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); |
821 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; | 860 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; |
822 | 861 | ||
823 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; | 862 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1]; |
824 | // OutPacket(handshake, ThrottleOutPacketType.Task); | 863 | handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block(); |
825 | // use same as MoveAgentIntoRegion (both should be task ) | 864 | handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; |
865 | handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported | ||
866 | |||
826 | OutPacket(handshake, ThrottleOutPacketType.Unknown); | 867 | OutPacket(handshake, ThrottleOutPacketType.Unknown); |
827 | } | 868 | } |
828 | 869 | ||
870 | |||
829 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) | 871 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) |
830 | { | 872 | { |
873 | m_thisAgentUpdateArgs.CameraAtAxis.X = float.MinValue; | ||
874 | m_thisAgentUpdateArgs.ControlFlags = uint.MaxValue; | ||
875 | |||
831 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); | 876 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); |
832 | mov.SimData.ChannelVersion = m_channelVersion; | 877 | mov.SimData.ChannelVersion = m_channelVersion; |
833 | mov.AgentData.SessionID = m_sessionId; | 878 | mov.AgentData.SessionID = m_sessionId; |
@@ -1210,9 +1255,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1210 | LLHeightFieldMoronize(map); | 1255 | LLHeightFieldMoronize(map); |
1211 | 1256 | ||
1212 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); | 1257 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); |
1213 | layerpack.Header.Reliable = true; | 1258 | |
1259 | // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience. | ||
1260 | // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain. | ||
1261 | // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area | ||
1262 | // invalidating previous packets for that area. | ||
1263 | |||
1264 | // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a | ||
1265 | // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower. | ||
1266 | |||
1267 | // One last note on this topic, by the time users are going to be editing the terrain, it's extremely likely that the sim will | ||
1268 | // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain | ||
1269 | // patches. | ||
1214 | 1270 | ||
1215 | OutPacket(layerpack, ThrottleOutPacketType.Task); | 1271 | // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss. |
1272 | if (m_justEditedTerrain) | ||
1273 | { | ||
1274 | layerpack.Header.Reliable = false; | ||
1275 | OutPacket(layerpack, | ||
1276 | ThrottleOutPacketType.Unknown ); | ||
1277 | } | ||
1278 | else | ||
1279 | { | ||
1280 | layerpack.Header.Reliable = true; | ||
1281 | OutPacket(layerpack, | ||
1282 | ThrottleOutPacketType.Task); | ||
1283 | } | ||
1216 | } | 1284 | } |
1217 | catch (Exception e) | 1285 | catch (Exception e) |
1218 | { | 1286 | { |
@@ -1405,6 +1473,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1405 | 1473 | ||
1406 | mapReply.AgentData.AgentID = AgentId; | 1474 | mapReply.AgentData.AgentID = AgentId; |
1407 | mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; | 1475 | mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; |
1476 | mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length]; | ||
1408 | mapReply.AgentData.Flags = flag; | 1477 | mapReply.AgentData.Flags = flag; |
1409 | 1478 | ||
1410 | for (int i = 0; i < mapBlocks2.Length; i++) | 1479 | for (int i = 0; i < mapBlocks2.Length; i++) |
@@ -1419,6 +1488,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1419 | mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; | 1488 | mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; |
1420 | mapReply.Data[i].Access = mapBlocks2[i].Access; | 1489 | mapReply.Data[i].Access = mapBlocks2[i].Access; |
1421 | mapReply.Data[i].Agents = mapBlocks2[i].Agents; | 1490 | mapReply.Data[i].Agents = mapBlocks2[i].Agents; |
1491 | |||
1492 | // TODO: hookup varregion sim size here | ||
1493 | mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock(); | ||
1494 | mapReply.Size[i].SizeX = 256; | ||
1495 | mapReply.Size[i].SizeY = 256; | ||
1422 | } | 1496 | } |
1423 | OutPacket(mapReply, ThrottleOutPacketType.Land); | 1497 | OutPacket(mapReply, ThrottleOutPacketType.Land); |
1424 | } | 1498 | } |
@@ -1578,13 +1652,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1578 | pc.PingID.OldestUnacked = 0; | 1652 | pc.PingID.OldestUnacked = 0; |
1579 | 1653 | ||
1580 | OutPacket(pc, ThrottleOutPacketType.Unknown); | 1654 | OutPacket(pc, ThrottleOutPacketType.Unknown); |
1655 | UDPClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount(); | ||
1581 | } | 1656 | } |
1582 | 1657 | ||
1583 | public void SendKillObject(ulong regionHandle, List<uint> localIDs) | 1658 | public void SendKillObject(List<uint> localIDs) |
1584 | { | 1659 | { |
1585 | // foreach (uint id in localIDs) | 1660 | // foreach (uint id in localIDs) |
1586 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); | 1661 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); |
1587 | 1662 | ||
1663 | // remove pending entities | ||
1664 | lock (m_entityProps.SyncRoot) | ||
1665 | m_entityProps.Remove(localIDs); | ||
1666 | lock (m_entityUpdates.SyncRoot) | ||
1667 | m_entityUpdates.Remove(localIDs); | ||
1668 | |||
1588 | KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); | 1669 | KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); |
1589 | // TODO: don't create new blocks if recycling an old packet | 1670 | // TODO: don't create new blocks if recycling an old packet |
1590 | kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count]; | 1671 | kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count]; |
@@ -1596,28 +1677,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1596 | kill.Header.Reliable = true; | 1677 | kill.Header.Reliable = true; |
1597 | kill.Header.Zerocoded = true; | 1678 | kill.Header.Zerocoded = true; |
1598 | 1679 | ||
1599 | if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null) | 1680 | OutPacket(kill, ThrottleOutPacketType.Task); |
1600 | { | 1681 | } |
1601 | OutPacket(kill, ThrottleOutPacketType.Task); | ||
1602 | } | ||
1603 | else | ||
1604 | { | ||
1605 | // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race | ||
1606 | // condition where a kill can be processed before an out-of-date update for the same object. | ||
1607 | // ProcessEntityUpdates() also takes the m_killRecord lock. | ||
1608 | // lock (m_killRecord) | ||
1609 | // { | ||
1610 | // foreach (uint localID in localIDs) | ||
1611 | // m_killRecord.Add(localID); | ||
1612 | |||
1613 | // The throttle queue used here must match that being used for updates. Otherwise, there is a | ||
1614 | // chance that a kill packet put on a separate queue will be sent to the client before an existing | ||
1615 | // update packet on another queue. Receiving updates after kills results in unowned and undeletable | ||
1616 | // scene objects in a viewer until that viewer is relogged in. | ||
1617 | OutPacket(kill, ThrottleOutPacketType.Task); | ||
1618 | // } | ||
1619 | } | ||
1620 | } | ||
1621 | 1682 | ||
1622 | /// <summary> | 1683 | /// <summary> |
1623 | /// Send information about the items contained in a folder to the client. | 1684 | /// Send information about the items contained in a folder to the client. |
@@ -2594,11 +2655,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2594 | { | 2655 | { |
2595 | AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); | 2656 | AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); |
2596 | avatarSitResponse.SitObject.ID = TargetID; | 2657 | avatarSitResponse.SitObject.ID = TargetID; |
2597 | if (CameraAtOffset != Vector3.Zero) | 2658 | avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset; |
2598 | { | 2659 | avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset; |
2599 | avatarSitResponse.SitTransform.CameraAtOffset = CameraAtOffset; | ||
2600 | avatarSitResponse.SitTransform.CameraEyeOffset = CameraEyeOffset; | ||
2601 | } | ||
2602 | avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; | 2660 | avatarSitResponse.SitTransform.ForceMouselook = ForceMouseLook; |
2603 | avatarSitResponse.SitTransform.AutoPilot = autopilot; | 2661 | avatarSitResponse.SitTransform.AutoPilot = autopilot; |
2604 | avatarSitResponse.SitTransform.SitPosition = OffsetPos; | 2662 | avatarSitResponse.SitTransform.SitPosition = OffsetPos; |
@@ -3630,8 +3688,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3630 | avp.Sender.IsTrial = false; | 3688 | avp.Sender.IsTrial = false; |
3631 | avp.Sender.ID = agentID; | 3689 | avp.Sender.ID = agentID; |
3632 | avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; | 3690 | avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; |
3691 | |||
3692 | // this need be use in future | ||
3693 | // avp.AppearanceData[0].AppearanceVersion = 0; | ||
3694 | // avp.AppearanceData[0].CofVersion = 0; | ||
3695 | |||
3633 | //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); | 3696 | //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); |
3634 | OutPacket(avp, ThrottleOutPacketType.Task); | 3697 | OutPacket(avp, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); |
3635 | } | 3698 | } |
3636 | 3699 | ||
3637 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) | 3700 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) |
@@ -3659,7 +3722,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3659 | ani.AnimationSourceList[i].ObjectID = objectIDs[i]; | 3722 | ani.AnimationSourceList[i].ObjectID = objectIDs[i]; |
3660 | } | 3723 | } |
3661 | ani.Header.Reliable = false; | 3724 | ani.Header.Reliable = false; |
3662 | OutPacket(ani, ThrottleOutPacketType.Task); | 3725 | OutPacket(ani, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); |
3663 | } | 3726 | } |
3664 | 3727 | ||
3665 | #endregion | 3728 | #endregion |
@@ -3688,7 +3751,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3688 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | 3751 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; |
3689 | objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence); | 3752 | objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence); |
3690 | 3753 | ||
3691 | OutPacket(objupdate, ThrottleOutPacketType.Task); | 3754 | OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); |
3692 | 3755 | ||
3693 | // We need to record the avatar local id since the root prim of an attachment points to this. | 3756 | // We need to record the avatar local id since the root prim of an attachment points to this. |
3694 | // m_attachmentsSent.Add(avatar.LocalId); | 3757 | // m_attachmentsSent.Add(avatar.LocalId); |
@@ -3751,8 +3814,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3751 | { | 3814 | { |
3752 | SceneObjectPart e = (SceneObjectPart)entity; | 3815 | SceneObjectPart e = (SceneObjectPart)entity; |
3753 | SceneObjectGroup g = e.ParentGroup; | 3816 | SceneObjectGroup g = e.ParentGroup; |
3754 | if (g.RootPart.Shape.State > 30) // HUD | 3817 | if (g.HasPrivateAttachmentPoint && g.OwnerID != AgentId) |
3755 | if (g.OwnerID != AgentId) | ||
3756 | return; // Don't send updates for other people's HUDs | 3818 | return; // Don't send updates for other people's HUDs |
3757 | } | 3819 | } |
3758 | 3820 | ||
@@ -3762,6 +3824,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3762 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); | 3824 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); |
3763 | } | 3825 | } |
3764 | 3826 | ||
3827 | |||
3765 | /// <summary> | 3828 | /// <summary> |
3766 | /// Requeue an EntityUpdate when it was not acknowledged by the client. | 3829 | /// Requeue an EntityUpdate when it was not acknowledged by the client. |
3767 | /// We will update the priority and put it in the correct queue, merging update flags | 3830 | /// We will update the priority and put it in the correct queue, merging update flags |
@@ -3769,8 +3832,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3769 | /// The original update time is used for the merged update. | 3832 | /// The original update time is used for the merged update. |
3770 | /// </summary> | 3833 | /// </summary> |
3771 | private void ResendPrimUpdate(EntityUpdate update) | 3834 | private void ResendPrimUpdate(EntityUpdate update) |
3772 | { | 3835 | { |
3773 | // If the update exists in priority queue, it will be updated. | 3836 | // If the update exists in priority queue, it will be updated. |
3774 | // If it does not exist then it will be added with the current (rather than its original) priority | 3837 | // If it does not exist then it will be added with the current (rather than its original) priority |
3775 | uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity); | 3838 | uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity); |
3776 | 3839 | ||
@@ -3796,10 +3859,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3796 | // Count this as a resent packet since we are going to requeue all of the updates contained in it | 3859 | // Count this as a resent packet since we are going to requeue all of the updates contained in it |
3797 | Interlocked.Increment(ref m_udpClient.PacketsResent); | 3860 | Interlocked.Increment(ref m_udpClient.PacketsResent); |
3798 | 3861 | ||
3862 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
3863 | // is 100% correct | ||
3864 | m_udpServer.PacketsResentCount++; | ||
3865 | |||
3799 | foreach (EntityUpdate update in updates) | 3866 | foreach (EntityUpdate update in updates) |
3800 | ResendPrimUpdate(update); | 3867 | ResendPrimUpdate(update); |
3801 | } | 3868 | } |
3802 | 3869 | ||
3803 | private void ProcessEntityUpdates(int maxUpdates) | 3870 | private void ProcessEntityUpdates(int maxUpdates) |
3804 | { | 3871 | { |
3805 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | 3872 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); |
@@ -3841,13 +3908,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3841 | { | 3908 | { |
3842 | SceneObjectPart part = (SceneObjectPart)update.Entity; | 3909 | SceneObjectPart part = (SceneObjectPart)update.Entity; |
3843 | 3910 | ||
3844 | if (part.ParentGroup.IsDeleted) | 3911 | if (part.ParentGroup.IsDeleted || part.ParentGroup.inTransit) |
3845 | continue; | 3912 | continue; |
3846 | 3913 | ||
3847 | if (part.ParentGroup.IsAttachment) | 3914 | if (part.ParentGroup.IsAttachment) |
3848 | { // Someone else's HUD, why are we getting these? | 3915 | { // Someone else's HUD, why are we getting these? |
3849 | if (part.ParentGroup.OwnerID != AgentId && | 3916 | if (part.ParentGroup.OwnerID != AgentId && part.ParentGroup.HasPrivateAttachmentPoint) |
3850 | part.ParentGroup.RootPart.Shape.State > 30) | ||
3851 | continue; | 3917 | continue; |
3852 | ScenePresence sp; | 3918 | ScenePresence sp; |
3853 | // Owner is not in the sim, don't update it to | 3919 | // Owner is not in the sim, don't update it to |
@@ -3879,36 +3945,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3879 | if (sp.IsChildAgent) | 3945 | if (sp.IsChildAgent) |
3880 | continue; | 3946 | continue; |
3881 | 3947 | ||
3882 | // If the object is an attachment we don't want it to be in the kill | ||
3883 | // record. Else attaching from inworld and subsequently dropping | ||
3884 | // it will no longer work. | ||
3885 | // lock (m_killRecord) | ||
3886 | // { | ||
3887 | // m_killRecord.Remove(part.LocalId); | ||
3888 | // m_killRecord.Remove(part.ParentGroup.RootPart.LocalId); | ||
3889 | // } | ||
3890 | } | ||
3891 | else | ||
3892 | { | ||
3893 | // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client | ||
3894 | // will never receive an update after a prim kill. Even then, keeping the kill record may be a good | ||
3895 | // safety measure. | ||
3896 | // | ||
3897 | // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update | ||
3898 | // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs | ||
3899 | // updates and kills on different threads with different scheduling strategies, hence this protection. | ||
3900 | // | ||
3901 | // This doesn't appear to apply to child prims - a client will happily ignore these updates | ||
3902 | // after the root prim has been deleted. | ||
3903 | // | ||
3904 | // We ignore this for attachments because attaching something from inworld breaks unless we do. | ||
3905 | // lock (m_killRecord) | ||
3906 | // { | ||
3907 | // if (m_killRecord.Contains(part.LocalId)) | ||
3908 | // continue; | ||
3909 | // if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId)) | ||
3910 | // continue; | ||
3911 | // } | ||
3912 | } | 3948 | } |
3913 | 3949 | ||
3914 | if (part.ParentGroup.IsAttachment && m_disableFacelights) | 3950 | if (part.ParentGroup.IsAttachment && m_disableFacelights) |
@@ -3939,7 +3975,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3939 | else if (update.Entity is ScenePresence) | 3975 | else if (update.Entity is ScenePresence) |
3940 | { | 3976 | { |
3941 | ScenePresence presence = (ScenePresence)update.Entity; | 3977 | ScenePresence presence = (ScenePresence)update.Entity; |
3942 | 3978 | if (presence.IsDeleted) | |
3979 | continue; | ||
3943 | // If ParentUUID is not UUID.Zero and ParentID is 0, this | 3980 | // If ParentUUID is not UUID.Zero and ParentID is 0, this |
3944 | // avatar is in the process of crossing regions while | 3981 | // avatar is in the process of crossing regions while |
3945 | // sat on an object. In this state, we don't want any | 3982 | // sat on an object. In this state, we don't want any |
@@ -4022,8 +4059,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4022 | } | 4059 | } |
4023 | else | 4060 | else |
4024 | { | 4061 | { |
4025 | if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) | 4062 | if (update.Entity is ScenePresence) |
4026 | // Self updates go into a special list | 4063 | // ALL presence updates go into a special list |
4027 | terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); | 4064 | terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); |
4028 | else | 4065 | else |
4029 | // Everything else goes here | 4066 | // Everything else goes here |
@@ -4035,7 +4072,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4035 | 4072 | ||
4036 | #region Packet Sending | 4073 | #region Packet Sending |
4037 | 4074 | ||
4038 | const float TIME_DILATION = 1.0f; | 4075 | // const float TIME_DILATION = 1.0f; |
4039 | ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); | 4076 | ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); |
4040 | 4077 | ||
4041 | if (terseAgentUpdateBlocks.IsValueCreated) | 4078 | if (terseAgentUpdateBlocks.IsValueCreated) |
@@ -4051,7 +4088,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4051 | for (int i = 0; i < blocks.Count; i++) | 4088 | for (int i = 0; i < blocks.Count; i++) |
4052 | packet.ObjectData[i] = blocks[i]; | 4089 | packet.ObjectData[i] = blocks[i]; |
4053 | 4090 | ||
4054 | OutPacket(packet, ThrottleOutPacketType.Unknown, true); | 4091 | OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); |
4055 | } | 4092 | } |
4056 | 4093 | ||
4057 | if (objectUpdateBlocks.IsValueCreated) | 4094 | if (objectUpdateBlocks.IsValueCreated) |
@@ -4097,13 +4134,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4097 | 4134 | ||
4098 | for (int i = 0; i < blocks.Count; i++) | 4135 | for (int i = 0; i < blocks.Count; i++) |
4099 | packet.ObjectData[i] = blocks[i]; | 4136 | packet.ObjectData[i] = blocks[i]; |
4100 | 4137 | ||
4101 | OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); | 4138 | OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); |
4102 | } | 4139 | } |
4103 | 4140 | ||
4104 | #endregion Packet Sending | 4141 | #endregion Packet Sending |
4105 | } | 4142 | } |
4106 | 4143 | ||
4144 | // hack.. dont use | ||
4145 | public void SendPartFullUpdate(ISceneEntity ent, uint? parentID) | ||
4146 | { | ||
4147 | if (ent is SceneObjectPart) | ||
4148 | { | ||
4149 | SceneObjectPart part = (SceneObjectPart)ent; | ||
4150 | ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | ||
4151 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
4152 | packet.RegionData.TimeDilation = 1; | ||
4153 | packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | ||
4154 | |||
4155 | ObjectUpdatePacket.ObjectDataBlock blk = CreatePrimUpdateBlock(part, this.m_agentId); | ||
4156 | if (parentID.HasValue) | ||
4157 | { | ||
4158 | blk.ParentID = parentID.Value; | ||
4159 | } | ||
4160 | |||
4161 | packet.ObjectData[0] = blk; | ||
4162 | |||
4163 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
4164 | } | ||
4165 | } | ||
4166 | |||
4107 | public void ReprioritizeUpdates() | 4167 | public void ReprioritizeUpdates() |
4108 | { | 4168 | { |
4109 | lock (m_entityUpdates.SyncRoot) | 4169 | lock (m_entityUpdates.SyncRoot) |
@@ -4140,8 +4200,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4140 | 4200 | ||
4141 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) | 4201 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) |
4142 | { | 4202 | { |
4203 | // if (!m_udpServer.IsRunningOutbound) | ||
4204 | // return; | ||
4205 | |||
4143 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | 4206 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) |
4144 | { | 4207 | { |
4208 | // if (!m_udpServer.IsRunningOutbound) | ||
4209 | // return; | ||
4210 | |||
4145 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) | 4211 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) |
4146 | { | 4212 | { |
4147 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; | 4213 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; |
@@ -4167,6 +4233,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4167 | ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); | 4233 | ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); |
4168 | } | 4234 | } |
4169 | 4235 | ||
4236 | internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories) | ||
4237 | { | ||
4238 | bool hasUpdates = false; | ||
4239 | |||
4240 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | ||
4241 | { | ||
4242 | if (m_entityUpdates.Count > 0) | ||
4243 | hasUpdates = true; | ||
4244 | else if (m_entityProps.Count > 0) | ||
4245 | hasUpdates = true; | ||
4246 | } | ||
4247 | |||
4248 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) | ||
4249 | { | ||
4250 | if (ImageManager.HasUpdates()) | ||
4251 | hasUpdates = true; | ||
4252 | } | ||
4253 | |||
4254 | return hasUpdates; | ||
4255 | } | ||
4256 | |||
4170 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) | 4257 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) |
4171 | { | 4258 | { |
4172 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); | 4259 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); |
@@ -4312,6 +4399,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4312 | // Count this as a resent packet since we are going to requeue all of the updates contained in it | 4399 | // Count this as a resent packet since we are going to requeue all of the updates contained in it |
4313 | Interlocked.Increment(ref m_udpClient.PacketsResent); | 4400 | Interlocked.Increment(ref m_udpClient.PacketsResent); |
4314 | 4401 | ||
4402 | // We're not going to worry about interlock yet since its not currently critical that this total count | ||
4403 | // is 100% correct | ||
4404 | m_udpServer.PacketsResentCount++; | ||
4405 | |||
4315 | foreach (ObjectPropertyUpdate update in updates) | 4406 | foreach (ObjectPropertyUpdate update in updates) |
4316 | ResendPropertyUpdate(update); | 4407 | ResendPropertyUpdate(update); |
4317 | } | 4408 | } |
@@ -4499,6 +4590,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4499 | SceneObjectPart root = sop.ParentGroup.RootPart; | 4590 | SceneObjectPart root = sop.ParentGroup.RootPart; |
4500 | 4591 | ||
4501 | block.TouchName = Util.StringToBytes256(root.TouchName); | 4592 | block.TouchName = Util.StringToBytes256(root.TouchName); |
4593 | |||
4594 | // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but | ||
4595 | // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached | ||
4596 | // copy is really needed since it's less efficient to be constantly recreating this byte array. | ||
4597 | // using (MemoryStream memStream = new MemoryStream()) | ||
4598 | // { | ||
4599 | // using (BinaryWriter binWriter = new BinaryWriter(memStream)) | ||
4600 | // { | ||
4601 | // for (int i = 0; i < sop.GetNumberOfSides(); i++) | ||
4602 | // { | ||
4603 | // Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i]; | ||
4604 | // | ||
4605 | // UUID textureID; | ||
4606 | // | ||
4607 | // if (teFace != null) | ||
4608 | // textureID = teFace.TextureID; | ||
4609 | // else | ||
4610 | // textureID = sop.Shape.Textures.DefaultTexture.TextureID; | ||
4611 | // | ||
4612 | // binWriter.Write(textureID.GetBytes()); | ||
4613 | // } | ||
4614 | // | ||
4615 | // block.TextureID = memStream.ToArray(); | ||
4616 | // } | ||
4617 | // } | ||
4618 | |||
4502 | block.TextureID = new byte[0]; // TextureID ??? | 4619 | block.TextureID = new byte[0]; // TextureID ??? |
4503 | block.SitName = Util.StringToBytes256(root.SitName); | 4620 | block.SitName = Util.StringToBytes256(root.SitName); |
4504 | block.OwnerMask = root.OwnerMask; | 4621 | block.OwnerMask = root.OwnerMask; |
@@ -4839,7 +4956,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4839 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); | 4956 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); |
4840 | if (eq != null) | 4957 | if (eq != null) |
4841 | { | 4958 | { |
4842 | eq.ParcelProperties(updateMessage, this.AgentId); | 4959 | |
4960 | OSD message_body = updateMessage.Serialize(); | ||
4961 | // Add new fields here until OMV has them | ||
4962 | OSDMap bodyMap = (OSDMap)message_body; | ||
4963 | OSDArray parcelDataArray = (OSDArray)bodyMap["ParcelData"]; | ||
4964 | OSDMap parcelData = (OSDMap)parcelDataArray[0]; | ||
4965 | parcelData["SeeAVs"] = OSD.FromBoolean(landData.SeeAVs); | ||
4966 | parcelData["AnyAVSounds"] = OSD.FromBoolean(landData.AnyAVSounds); | ||
4967 | parcelData["GroupAVSounds"] = OSD.FromBoolean(landData.GroupAVSounds); | ||
4968 | OSDMap message = new OSDMap(); | ||
4969 | message.Add("message", OSD.FromString("ParcelProperties")); | ||
4970 | message.Add("body", message_body); | ||
4971 | |||
4972 | eq.Enqueue (message, this.AgentId); | ||
4973 | |||
4974 | // eq.ParcelProperties(updateMessage, this.AgentId); | ||
4843 | } | 4975 | } |
4844 | else | 4976 | else |
4845 | { | 4977 | { |
@@ -4877,7 +5009,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4877 | 5009 | ||
4878 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) | 5010 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) |
4879 | { | 5011 | { |
4880 | m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); | 5012 | // m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); |
4881 | 5013 | ||
4882 | bool firstCall = true; | 5014 | bool firstCall = true; |
4883 | const int MAX_OBJECTS_PER_PACKET = 251; | 5015 | const int MAX_OBJECTS_PER_PACKET = 251; |
@@ -4997,35 +5129,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4997 | 5129 | ||
4998 | position = presence.OffsetPosition; | 5130 | position = presence.OffsetPosition; |
4999 | rotation = presence.Rotation; | 5131 | rotation = presence.Rotation; |
5000 | 5132 | angularVelocity = presence.AngularVelocity; | |
5001 | if (presence.ParentID != 0) | 5133 | rotation = presence.Rotation; |
5002 | { | ||
5003 | SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID); | ||
5004 | if (part != null && part != part.ParentGroup.RootPart) | ||
5005 | { | ||
5006 | position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset; | ||
5007 | rotation = part.RotationOffset * presence.Rotation; | ||
5008 | } | ||
5009 | angularVelocity = Vector3.Zero; | ||
5010 | } | ||
5011 | else | ||
5012 | { | ||
5013 | angularVelocity = presence.AngularVelocity; | ||
5014 | rotation = presence.Rotation; | ||
5015 | } | ||
5016 | 5134 | ||
5017 | attachPoint = 0; | 5135 | attachPoint = 0; |
5136 | // m_log.DebugFormat( | ||
5137 | // "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name); | ||
5138 | |||
5139 | // attachPoint = presence.State; // Core: commented | ||
5018 | collisionPlane = presence.CollisionPlane; | 5140 | collisionPlane = presence.CollisionPlane; |
5019 | velocity = presence.Velocity; | 5141 | velocity = presence.Velocity; |
5020 | acceleration = Vector3.Zero; | 5142 | acceleration = Vector3.Zero; |
5021 | 5143 | ||
5022 | // Interestingly, sending this to non-zero will cause the client's avatar to start moving & accelerating | ||
5023 | // in that direction, even though we don't model this on the server. Implementing this in the future | ||
5024 | // may improve movement smoothness. | ||
5025 | // acceleration = new Vector3(1, 0, 0); | ||
5026 | |||
5027 | if (sendTexture) | 5144 | if (sendTexture) |
5145 | { | ||
5028 | textureEntry = presence.Appearance.Texture.GetBytes(); | 5146 | textureEntry = presence.Appearance.Texture.GetBytes(); |
5147 | } | ||
5029 | else | 5148 | else |
5030 | textureEntry = null; | 5149 | textureEntry = null; |
5031 | } | 5150 | } |
@@ -5034,7 +5153,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5034 | SceneObjectPart part = (SceneObjectPart)entity; | 5153 | SceneObjectPart part = (SceneObjectPart)entity; |
5035 | 5154 | ||
5036 | attachPoint = part.ParentGroup.AttachmentPoint; | 5155 | attachPoint = part.ParentGroup.AttachmentPoint; |
5037 | 5156 | attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16)); | |
5038 | // m_log.DebugFormat( | 5157 | // m_log.DebugFormat( |
5039 | // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", | 5158 | // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", |
5040 | // attachPoint, part.Name, part.LocalId, Name); | 5159 | // attachPoint, part.Name, part.LocalId, Name); |
@@ -5062,7 +5181,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5062 | pos += 4; | 5181 | pos += 4; |
5063 | 5182 | ||
5064 | // Avatar/CollisionPlane | 5183 | // Avatar/CollisionPlane |
5065 | data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; | 5184 | data[pos++] = (byte) attachPoint; |
5066 | if (avatar) | 5185 | if (avatar) |
5067 | { | 5186 | { |
5068 | data[pos++] = 1; | 5187 | data[pos++] = 1; |
@@ -5132,30 +5251,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5132 | Vector3 offsetPosition = data.OffsetPosition; | 5251 | Vector3 offsetPosition = data.OffsetPosition; |
5133 | Quaternion rotation = data.Rotation; | 5252 | Quaternion rotation = data.Rotation; |
5134 | uint parentID = data.ParentID; | 5253 | uint parentID = data.ParentID; |
5135 | 5254 | ||
5136 | if (parentID != 0) | 5255 | // m_log.DebugFormat( |
5137 | { | 5256 | // "[LLCLIENTVIEW]: Sending full update to {0} with position {1} in {2}", Name, data.OffsetPosition, m_scene.Name); |
5138 | SceneObjectPart part = m_scene.GetSceneObjectPart(parentID); | ||
5139 | if (part != null && part != part.ParentGroup.RootPart) | ||
5140 | { | ||
5141 | offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset; | ||
5142 | rotation = part.RotationOffset * data.Rotation; | ||
5143 | parentID = part.ParentGroup.RootPart.LocalId; | ||
5144 | } | ||
5145 | } | ||
5146 | 5257 | ||
5147 | byte[] objectData = new byte[76]; | 5258 | byte[] objectData = new byte[76]; |
5148 | 5259 | ||
5149 | data.CollisionPlane.ToBytes(objectData, 0); | ||
5150 | offsetPosition.ToBytes(objectData, 16); | ||
5151 | Vector3 velocity = new Vector3(0, 0, 0); | 5260 | Vector3 velocity = new Vector3(0, 0, 0); |
5152 | Vector3 acceleration = new Vector3(0, 0, 0); | 5261 | Vector3 acceleration = new Vector3(0, 0, 0); |
5262 | rotation.Normalize(); | ||
5263 | |||
5264 | data.CollisionPlane.ToBytes(objectData, 0); | ||
5265 | offsetPosition.ToBytes(objectData, 16); | ||
5153 | velocity.ToBytes(objectData, 28); | 5266 | velocity.ToBytes(objectData, 28); |
5154 | acceleration.ToBytes(objectData, 40); | 5267 | acceleration.ToBytes(objectData, 40); |
5155 | // data.Velocity.ToBytes(objectData, 28); | ||
5156 | // data.Acceleration.ToBytes(objectData, 40); | ||
5157 | rotation.ToBytes(objectData, 52); | 5268 | rotation.ToBytes(objectData, 52); |
5158 | //data.AngularVelocity.ToBytes(objectData, 64); | 5269 | data.AngularVelocity.ToBytes(objectData, 64); |
5159 | 5270 | ||
5160 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | 5271 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); |
5161 | 5272 | ||
@@ -5168,7 +5279,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5168 | update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + | 5279 | update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + |
5169 | data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); | 5280 | data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); |
5170 | update.ObjectData = objectData; | 5281 | update.ObjectData = objectData; |
5171 | update.ParentID = parentID; | 5282 | |
5283 | SceneObjectPart parentPart = data.ParentPart; | ||
5284 | if (parentPart != null) | ||
5285 | update.ParentID = parentPart.ParentGroup.LocalId; | ||
5286 | else | ||
5287 | update.ParentID = 0; | ||
5288 | |||
5172 | update.PathCurve = 16; | 5289 | update.PathCurve = 16; |
5173 | update.PathScaleX = 100; | 5290 | update.PathScaleX = 100; |
5174 | update.PathScaleY = 100; | 5291 | update.PathScaleY = 100; |
@@ -5205,15 +5322,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5205 | data.RelativePosition.ToBytes(objectData, 0); | 5322 | data.RelativePosition.ToBytes(objectData, 0); |
5206 | data.Velocity.ToBytes(objectData, 12); | 5323 | data.Velocity.ToBytes(objectData, 12); |
5207 | data.Acceleration.ToBytes(objectData, 24); | 5324 | data.Acceleration.ToBytes(objectData, 24); |
5208 | try | 5325 | |
5209 | { | 5326 | Quaternion rotation = data.RotationOffset; |
5210 | data.RotationOffset.ToBytes(objectData, 36); | 5327 | rotation.Normalize(); |
5211 | } | 5328 | rotation.ToBytes(objectData, 36); |
5212 | catch (Exception e) | ||
5213 | { | ||
5214 | m_log.Warn("[LLClientView]: exception converting quaternion to bytes, using Quaternion.Identity. Exception: " + e.ToString()); | ||
5215 | OpenMetaverse.Quaternion.Identity.ToBytes(objectData, 36); | ||
5216 | } | ||
5217 | data.AngularVelocity.ToBytes(objectData, 48); | 5329 | data.AngularVelocity.ToBytes(objectData, 48); |
5218 | 5330 | ||
5219 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | 5331 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); |
@@ -5227,6 +5339,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5227 | //update.JointType = 0; | 5339 | //update.JointType = 0; |
5228 | update.Material = data.Material; | 5340 | update.Material = data.Material; |
5229 | update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim | 5341 | update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim |
5342 | /* | ||
5230 | if (data.ParentGroup.IsAttachment) | 5343 | if (data.ParentGroup.IsAttachment) |
5231 | { | 5344 | { |
5232 | update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.ParentGroup.FromItemID); | 5345 | update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.ParentGroup.FromItemID); |
@@ -5240,6 +5353,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5240 | // case for attachments may contain conflicting values that can end up crashing the viewer. | 5353 | // case for attachments may contain conflicting values that can end up crashing the viewer. |
5241 | update.State = data.ParentGroup.RootPart.Shape.State; | 5354 | update.State = data.ParentGroup.RootPart.Shape.State; |
5242 | } | 5355 | } |
5356 | */ | ||
5357 | |||
5358 | if (data.ParentGroup.IsAttachment) | ||
5359 | { | ||
5360 | if (data.IsRoot) | ||
5361 | { | ||
5362 | update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.ParentGroup.FromItemID); | ||
5363 | } | ||
5364 | else | ||
5365 | update.NameValue = Utils.EmptyBytes; | ||
5366 | |||
5367 | int st = (int)data.ParentGroup.AttachmentPoint; | ||
5368 | update.State = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ; | ||
5369 | } | ||
5370 | else | ||
5371 | { | ||
5372 | update.NameValue = Utils.EmptyBytes; | ||
5373 | update.State = data.Shape.State; // not sure about this | ||
5374 | } | ||
5375 | |||
5243 | 5376 | ||
5244 | // m_log.DebugFormat( | 5377 | // m_log.DebugFormat( |
5245 | // "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}", | 5378 | // "[LLCLIENTVIEW]: Sending state {0} for {1} {2} to {3}", |
@@ -5387,7 +5520,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5387 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); | 5520 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); |
5388 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); | 5521 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); |
5389 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); | 5522 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); |
5390 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); | 5523 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false); |
5391 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); | 5524 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); |
5392 | AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); | 5525 | AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); |
5393 | AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); | 5526 | AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); |
@@ -5448,8 +5581,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5448 | AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); | 5581 | AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); |
5449 | AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); | 5582 | AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); |
5450 | AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); | 5583 | AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); |
5451 | AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); | 5584 | AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false); |
5452 | AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); | 5585 | AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false); |
5453 | AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); | 5586 | AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); |
5454 | AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); | 5587 | AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); |
5455 | AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); | 5588 | AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); |
@@ -5481,7 +5614,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5481 | AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); | 5614 | AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); |
5482 | AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); | 5615 | AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); |
5483 | AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); | 5616 | AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); |
5484 | AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); | 5617 | AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false); |
5485 | AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); | 5618 | AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); |
5486 | AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); | 5619 | AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); |
5487 | AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); | 5620 | AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); |
@@ -5594,82 +5727,146 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5594 | 5727 | ||
5595 | #region Packet Handlers | 5728 | #region Packet Handlers |
5596 | 5729 | ||
5730 | public int TotalAgentUpdates { get; set; } | ||
5731 | |||
5597 | #region Scene/Avatar | 5732 | #region Scene/Avatar |
5598 | 5733 | ||
5599 | private bool HandleAgentUpdate(IClientAPI sener, Packet packet) | 5734 | // Threshold for body rotation to be a significant agent update |
5735 | // use the abs of cos | ||
5736 | private const float QDELTABody = 1.0f - 0.0001f; | ||
5737 | private const float QDELTAHead = 1.0f - 0.0001f; | ||
5738 | // Threshold for camera rotation to be a significant agent update | ||
5739 | private const float VDELTA = 0.01f; | ||
5740 | |||
5741 | /// <summary> | ||
5742 | /// This checks the update significance against the last update made. | ||
5743 | /// </summary> | ||
5744 | /// <remarks>Can only be called by one thread at a time</remarks> | ||
5745 | /// <returns></returns> | ||
5746 | /// <param name='x'></param> | ||
5747 | public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) | ||
5600 | { | 5748 | { |
5601 | if (OnAgentUpdate != null) | 5749 | return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); |
5750 | } | ||
5751 | |||
5752 | /// <summary> | ||
5753 | /// This checks the movement/state update significance against the last update made. | ||
5754 | /// </summary> | ||
5755 | /// <remarks>Can only be called by one thread at a time</remarks> | ||
5756 | /// <returns></returns> | ||
5757 | /// <param name='x'></param> | ||
5758 | private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) | ||
5759 | { | ||
5760 | float qdelta1 = Math.Abs(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation)); | ||
5761 | //qdelta2 = Math.Abs(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation)); | ||
5762 | |||
5763 | bool movementSignificant = | ||
5764 | (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed | ||
5765 | || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands | ||
5766 | || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed | ||
5767 | || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed | ||
5768 | || (qdelta1 < QDELTABody) // significant if body rotation above(below cos) threshold | ||
5769 | // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack | ||
5770 | // || (qdelta2 < QDELTAHead) // significant if head rotation above(below cos) threshold | ||
5771 | || (Math.Abs(x.Far - m_thisAgentUpdateArgs.Far) >= 32) // significant if far distance changed | ||
5772 | ; | ||
5773 | //if (movementSignificant) | ||
5774 | //{ | ||
5775 | //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", | ||
5776 | // qdelta1, qdelta2); | ||
5777 | //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", | ||
5778 | // x.ControlFlags, x.Flags, x.Far, x.State); | ||
5779 | //} | ||
5780 | return movementSignificant; | ||
5781 | } | ||
5782 | |||
5783 | /// <summary> | ||
5784 | /// This checks the camera update significance against the last update made. | ||
5785 | /// </summary> | ||
5786 | /// <remarks>Can only be called by one thread at a time</remarks> | ||
5787 | /// <returns></returns> | ||
5788 | /// <param name='x'></param> | ||
5789 | private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) | ||
5790 | { | ||
5791 | float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); | ||
5792 | float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); | ||
5793 | float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); | ||
5794 | float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); | ||
5795 | |||
5796 | bool cameraSignificant = | ||
5797 | (vdelta1 > VDELTA) || | ||
5798 | (vdelta2 > VDELTA) || | ||
5799 | (vdelta3 > VDELTA) || | ||
5800 | (vdelta4 > VDELTA) | ||
5801 | ; | ||
5802 | |||
5803 | //if (cameraSignificant) | ||
5804 | //{ | ||
5805 | //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", | ||
5806 | // x.CameraAtAxis, x.CameraCenter); | ||
5807 | //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", | ||
5808 | // x.CameraLeftAxis, x.CameraUpAxis); | ||
5809 | //} | ||
5810 | |||
5811 | return cameraSignificant; | ||
5812 | } | ||
5813 | |||
5814 | private bool HandleAgentUpdate(IClientAPI sender, Packet packet) | ||
5815 | { | ||
5816 | // We got here, which means that something in agent update was significant | ||
5817 | |||
5818 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | ||
5819 | AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; | ||
5820 | |||
5821 | if (x.AgentID != AgentId || x.SessionID != SessionId) | ||
5602 | { | 5822 | { |
5603 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | 5823 | PacketPool.Instance.ReturnPacket(packet); |
5824 | return false; | ||
5825 | } | ||
5604 | 5826 | ||
5605 | #region Packet Session and User Check | 5827 | TotalAgentUpdates++; |
5606 | if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) | ||
5607 | { | ||
5608 | PacketPool.Instance.ReturnPacket(packet); | ||
5609 | return false; | ||
5610 | } | ||
5611 | #endregion | ||
5612 | 5828 | ||
5613 | bool update = false; | 5829 | bool movement = CheckAgentMovementUpdateSignificance(x); |
5614 | AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; | 5830 | bool camera = CheckAgentCameraUpdateSignificance(x); |
5615 | |||
5616 | if (m_lastAgentUpdateArgs != null) | ||
5617 | { | ||
5618 | // These should be ordered from most-likely to | ||
5619 | // least likely to change. I've made an initial | ||
5620 | // guess at that. | ||
5621 | update = | ||
5622 | ( | ||
5623 | (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || | ||
5624 | (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || | ||
5625 | (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || | ||
5626 | (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || | ||
5627 | (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || | ||
5628 | (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || | ||
5629 | (x.ControlFlags != 0) || | ||
5630 | (x.Far != m_lastAgentUpdateArgs.Far) || | ||
5631 | (x.Flags != m_lastAgentUpdateArgs.Flags) || | ||
5632 | (x.State != m_lastAgentUpdateArgs.State) || | ||
5633 | (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || | ||
5634 | (x.SessionID != m_lastAgentUpdateArgs.SessionID) || | ||
5635 | (x.AgentID != m_lastAgentUpdateArgs.AgentID) | ||
5636 | ); | ||
5637 | } | ||
5638 | else | ||
5639 | { | ||
5640 | m_lastAgentUpdateArgs = new AgentUpdateArgs(); | ||
5641 | update = true; | ||
5642 | } | ||
5643 | 5831 | ||
5644 | if (update) | 5832 | // Was there a significant movement/state change? |
5645 | { | 5833 | if (movement) |
5646 | // m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); | 5834 | { |
5835 | m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; | ||
5836 | m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; | ||
5837 | m_thisAgentUpdateArgs.Far = x.Far; | ||
5838 | m_thisAgentUpdateArgs.Flags = x.Flags; | ||
5839 | m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; | ||
5840 | // m_thisAgentUpdateArgs.SessionID = x.SessionID; | ||
5841 | m_thisAgentUpdateArgs.State = x.State; | ||
5647 | 5842 | ||
5648 | m_lastAgentUpdateArgs.AgentID = x.AgentID; | 5843 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; |
5649 | m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; | 5844 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; |
5650 | m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; | ||
5651 | m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; | ||
5652 | m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; | ||
5653 | m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; | ||
5654 | m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; | ||
5655 | m_lastAgentUpdateArgs.Far = x.Far; | ||
5656 | m_lastAgentUpdateArgs.Flags = x.Flags; | ||
5657 | m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation; | ||
5658 | m_lastAgentUpdateArgs.SessionID = x.SessionID; | ||
5659 | m_lastAgentUpdateArgs.State = x.State; | ||
5660 | 5845 | ||
5661 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; | 5846 | if (handlerPreAgentUpdate != null) |
5662 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; | 5847 | OnPreAgentUpdate(this, m_thisAgentUpdateArgs); |
5663 | 5848 | ||
5664 | if (handlerPreAgentUpdate != null) | 5849 | if (handlerAgentUpdate != null) |
5665 | OnPreAgentUpdate(this, m_lastAgentUpdateArgs); | 5850 | OnAgentUpdate(this, m_thisAgentUpdateArgs); |
5666 | 5851 | ||
5667 | if (handlerAgentUpdate != null) | 5852 | handlerAgentUpdate = null; |
5668 | OnAgentUpdate(this, m_lastAgentUpdateArgs); | 5853 | handlerPreAgentUpdate = null; |
5854 | } | ||
5669 | 5855 | ||
5670 | handlerAgentUpdate = null; | 5856 | // Was there a significant camera(s) change? |
5671 | handlerPreAgentUpdate = null; | 5857 | if (camera) |
5672 | } | 5858 | { |
5859 | m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; | ||
5860 | m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; | ||
5861 | m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; | ||
5862 | m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; | ||
5863 | |||
5864 | UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate; | ||
5865 | |||
5866 | if (handlerAgentCameraUpdate != null) | ||
5867 | handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs); | ||
5868 | |||
5869 | handlerAgentCameraUpdate = null; | ||
5673 | } | 5870 | } |
5674 | 5871 | ||
5675 | PacketPool.Instance.ReturnPacket(packet); | 5872 | PacketPool.Instance.ReturnPacket(packet); |
@@ -6260,6 +6457,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6260 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); | 6457 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); |
6261 | if (modify.ParcelData.Length > 0) | 6458 | if (modify.ParcelData.Length > 0) |
6262 | { | 6459 | { |
6460 | // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore, | ||
6461 | // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit. | ||
6462 | m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable | ||
6263 | if (OnModifyTerrain != null) | 6463 | if (OnModifyTerrain != null) |
6264 | { | 6464 | { |
6265 | for (int i = 0; i < modify.ParcelData.Length; i++) | 6465 | for (int i = 0; i < modify.ParcelData.Length; i++) |
@@ -6275,6 +6475,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6275 | } | 6475 | } |
6276 | } | 6476 | } |
6277 | } | 6477 | } |
6478 | m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again | ||
6278 | } | 6479 | } |
6279 | 6480 | ||
6280 | return true; | 6481 | return true; |
@@ -6343,7 +6544,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6343 | 6544 | ||
6344 | WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; | 6545 | WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; |
6345 | for (int i=0; i<appear.WearableData.Length;i++) | 6546 | for (int i=0; i<appear.WearableData.Length;i++) |
6346 | cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)}; | 6547 | cacheitems[i] = new WearableCacheItem(){ |
6548 | CacheId = appear.WearableData[i].CacheID, | ||
6549 | TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex) | ||
6550 | }; | ||
6347 | 6551 | ||
6348 | 6552 | ||
6349 | 6553 | ||
@@ -6549,8 +6753,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6549 | return true; | 6753 | return true; |
6550 | } | 6754 | } |
6551 | 6755 | ||
6552 | private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) | 6756 | private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) |
6553 | { | 6757 | { |
6758 | m_log.DebugFormat("[LLClientView] HandleCompleteAgentMovement"); | ||
6759 | |||
6554 | Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; | 6760 | Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; |
6555 | if (handlerCompleteMovementToRegion != null) | 6761 | if (handlerCompleteMovementToRegion != null) |
6556 | { | 6762 | { |
@@ -6636,6 +6842,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6636 | } | 6842 | } |
6637 | #endregion | 6843 | #endregion |
6638 | 6844 | ||
6845 | if (SceneAgent.IsChildAgent) | ||
6846 | { | ||
6847 | SendCantSitBecauseChildAgentResponse(); | ||
6848 | return true; | ||
6849 | } | ||
6850 | |||
6639 | AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; | 6851 | AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; |
6640 | 6852 | ||
6641 | if (handlerAgentRequestSit != null) | 6853 | if (handlerAgentRequestSit != null) |
@@ -6660,6 +6872,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6660 | } | 6872 | } |
6661 | #endregion | 6873 | #endregion |
6662 | 6874 | ||
6875 | if (SceneAgent.IsChildAgent) | ||
6876 | { | ||
6877 | SendCantSitBecauseChildAgentResponse(); | ||
6878 | return true; | ||
6879 | } | ||
6880 | |||
6663 | AgentSit handlerAgentSit = OnAgentSit; | 6881 | AgentSit handlerAgentSit = OnAgentSit; |
6664 | if (handlerAgentSit != null) | 6882 | if (handlerAgentSit != null) |
6665 | { | 6883 | { |
@@ -6669,6 +6887,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6669 | return true; | 6887 | return true; |
6670 | } | 6888 | } |
6671 | 6889 | ||
6890 | /// <summary> | ||
6891 | /// Used when a child agent gets a sit response which should not be fulfilled. | ||
6892 | /// </summary> | ||
6893 | private void SendCantSitBecauseChildAgentResponse() | ||
6894 | { | ||
6895 | SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you."); | ||
6896 | } | ||
6897 | |||
6672 | private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) | 6898 | private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) |
6673 | { | 6899 | { |
6674 | SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; | 6900 | SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; |
@@ -7879,129 +8105,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7879 | //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); | 8105 | //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); |
7880 | 8106 | ||
7881 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; | 8107 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; |
7882 | //m_log.Debug("Transfer Request: " + transfer.ToString()); | ||
7883 | // Validate inventory transfers | ||
7884 | // Has to be done here, because AssetCache can't do it | ||
7885 | // | ||
7886 | UUID taskID = UUID.Zero; | 8108 | UUID taskID = UUID.Zero; |
7887 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) | 8109 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) |
7888 | { | 8110 | { |
7889 | taskID = new UUID(transfer.TransferInfo.Params, 48); | ||
7890 | UUID itemID = new UUID(transfer.TransferInfo.Params, 64); | ||
7891 | UUID requestID = new UUID(transfer.TransferInfo.Params, 80); | ||
7892 | |||
7893 | // m_log.DebugFormat( | ||
7894 | // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", | ||
7895 | // requestID, itemID, taskID, Name); | ||
7896 | |||
7897 | if (!(((Scene)m_scene).Permissions.BypassPermissions())) | 8111 | if (!(((Scene)m_scene).Permissions.BypassPermissions())) |
7898 | { | 8112 | { |
7899 | if (taskID != UUID.Zero) // Prim | 8113 | // We're spawning a thread because the permissions check can block this thread |
8114 | Util.FireAndForget(delegate | ||
7900 | { | 8115 | { |
7901 | SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); | 8116 | // This requests the asset if needed |
8117 | HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer); | ||
8118 | }); | ||
8119 | return true; | ||
8120 | } | ||
8121 | } | ||
8122 | else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) | ||
8123 | { | ||
8124 | //TransferRequestPacket does not include covenant uuid? | ||
8125 | //get scene covenant uuid | ||
8126 | taskID = m_scene.RegionInfo.RegionSettings.Covenant; | ||
8127 | } | ||
7902 | 8128 | ||
7903 | if (part == null) | 8129 | // This is non-blocking |
7904 | { | 8130 | MakeAssetRequest(transfer, taskID); |
7905 | m_log.WarnFormat( | ||
7906 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", | ||
7907 | Name, requestID, itemID, taskID); | ||
7908 | return true; | ||
7909 | } | ||
7910 | 8131 | ||
7911 | TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); | 8132 | return true; |
7912 | if (tii == null) | 8133 | } |
7913 | { | ||
7914 | m_log.WarnFormat( | ||
7915 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", | ||
7916 | Name, requestID, itemID, taskID); | ||
7917 | return true; | ||
7918 | } | ||
7919 | 8134 | ||
7920 | if (tii.Type == (int)AssetType.LSLText) | 8135 | private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer) |
7921 | { | 8136 | { |
7922 | if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) | 8137 | UUID taskID = new UUID(transfer.TransferInfo.Params, 48); |
7923 | return true; | 8138 | UUID itemID = new UUID(transfer.TransferInfo.Params, 64); |
7924 | } | 8139 | UUID requestID = new UUID(transfer.TransferInfo.Params, 80); |
7925 | else if (tii.Type == (int)AssetType.Notecard) | ||
7926 | { | ||
7927 | if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId)) | ||
7928 | return true; | ||
7929 | } | ||
7930 | else | ||
7931 | { | ||
7932 | // TODO: Change this code to allow items other than notecards and scripts to be successfully | ||
7933 | // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule | ||
7934 | if (part.OwnerID != AgentId) | ||
7935 | { | ||
7936 | m_log.WarnFormat( | ||
7937 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", | ||
7938 | Name, requestID, itemID, taskID, part.OwnerID); | ||
7939 | return true; | ||
7940 | } | ||
7941 | 8140 | ||
7942 | if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) | 8141 | //m_log.DebugFormat( |
7943 | { | 8142 | // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", |
7944 | m_log.WarnFormat( | 8143 | // requestID, itemID, taskID, Name); |
7945 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", | ||
7946 | Name, requestID, itemID, taskID); | ||
7947 | return true; | ||
7948 | } | ||
7949 | 8144 | ||
7950 | if (tii.OwnerID != AgentId) | 8145 | //m_log.Debug("Transfer Request: " + transfer.ToString()); |
7951 | { | 8146 | // Validate inventory transfers |
7952 | m_log.WarnFormat( | 8147 | // Has to be done here, because AssetCache can't do it |
7953 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", | 8148 | // |
7954 | Name, requestID, itemID, taskID, tii.OwnerID); | 8149 | if (taskID != UUID.Zero) // Prim |
7955 | return true; | 8150 | { |
7956 | } | 8151 | SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); |
7957 | 8152 | ||
7958 | if (( | 8153 | if (part == null) |
7959 | tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | 8154 | { |
7960 | != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | 8155 | m_log.WarnFormat( |
7961 | { | 8156 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", |
7962 | m_log.WarnFormat( | 8157 | Name, requestID, itemID, taskID); |
7963 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", | 8158 | return; |
7964 | Name, requestID, itemID, taskID); | 8159 | } |
7965 | return true; | ||
7966 | } | ||
7967 | 8160 | ||
7968 | if (tii.AssetID != requestID) | 8161 | TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); |
7969 | { | 8162 | if (tii == null) |
7970 | m_log.WarnFormat( | 8163 | { |
7971 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", | 8164 | m_log.WarnFormat( |
7972 | Name, requestID, itemID, taskID, tii.AssetID); | 8165 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", |
7973 | return true; | 8166 | Name, requestID, itemID, taskID); |
7974 | } | 8167 | return; |
7975 | } | 8168 | } |
8169 | |||
8170 | if (tii.Type == (int)AssetType.LSLText) | ||
8171 | { | ||
8172 | if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) | ||
8173 | return; | ||
8174 | } | ||
8175 | else if (tii.Type == (int)AssetType.Notecard) | ||
8176 | { | ||
8177 | if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId)) | ||
8178 | return; | ||
8179 | } | ||
8180 | else | ||
8181 | { | ||
8182 | // TODO: Change this code to allow items other than notecards and scripts to be successfully | ||
8183 | // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule | ||
8184 | if (part.OwnerID != AgentId) | ||
8185 | { | ||
8186 | m_log.WarnFormat( | ||
8187 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", | ||
8188 | Name, requestID, itemID, taskID, part.OwnerID); | ||
8189 | return; | ||
7976 | } | 8190 | } |
7977 | else // Agent | 8191 | |
8192 | if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) | ||
7978 | { | 8193 | { |
7979 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | 8194 | m_log.WarnFormat( |
7980 | if (invAccess != null) | 8195 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", |
7981 | { | 8196 | Name, requestID, itemID, taskID); |
7982 | if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) | 8197 | return; |
7983 | return false; | 8198 | } |
7984 | } | 8199 | |
7985 | else | 8200 | if (tii.OwnerID != AgentId) |
7986 | { | 8201 | { |
7987 | return false; | 8202 | m_log.WarnFormat( |
7988 | } | 8203 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", |
8204 | Name, requestID, itemID, taskID, tii.OwnerID); | ||
8205 | return; | ||
8206 | } | ||
8207 | |||
8208 | if (( | ||
8209 | tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | ||
8210 | != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) | ||
8211 | { | ||
8212 | m_log.WarnFormat( | ||
8213 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", | ||
8214 | Name, requestID, itemID, taskID); | ||
8215 | return; | ||
8216 | } | ||
8217 | |||
8218 | if (tii.AssetID != requestID) | ||
8219 | { | ||
8220 | m_log.WarnFormat( | ||
8221 | "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", | ||
8222 | Name, requestID, itemID, taskID, tii.AssetID); | ||
8223 | return; | ||
7989 | } | 8224 | } |
7990 | } | 8225 | } |
7991 | } | 8226 | } |
7992 | else | 8227 | else // Agent |
7993 | if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) | 8228 | { |
8229 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | ||
8230 | if (invAccess != null) | ||
8231 | { | ||
8232 | if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) | ||
8233 | return; | ||
8234 | } | ||
8235 | else | ||
7994 | { | 8236 | { |
7995 | //TransferRequestPacket does not include covenant uuid? | 8237 | return; |
7996 | //get scene covenant uuid | ||
7997 | taskID = m_scene.RegionInfo.RegionSettings.Covenant; | ||
7998 | } | 8238 | } |
8239 | } | ||
7999 | 8240 | ||
8241 | // Permissions out of the way, let's request the asset | ||
8000 | MakeAssetRequest(transfer, taskID); | 8242 | MakeAssetRequest(transfer, taskID); |
8001 | 8243 | ||
8002 | return true; | ||
8003 | } | 8244 | } |
8004 | 8245 | ||
8246 | |||
8005 | private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) | 8247 | private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) |
8006 | { | 8248 | { |
8007 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; | 8249 | AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; |
@@ -11732,8 +11974,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11732 | } | 11974 | } |
11733 | 11975 | ||
11734 | /// <summary> | 11976 | /// <summary> |
11735 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | ||
11736 | /// its appearance texture cached. | ||
11737 | /// </summary> | 11977 | /// </summary> |
11738 | /// <remarks> | 11978 | /// <remarks> |
11739 | /// At the moment, we always reply that there is no cached texture. | 11979 | /// At the moment, we always reply that there is no cached texture. |
@@ -11741,6 +11981,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11741 | /// <param name="simclient"></param> | 11981 | /// <param name="simclient"></param> |
11742 | /// <param name="packet"></param> | 11982 | /// <param name="packet"></param> |
11743 | /// <returns></returns> | 11983 | /// <returns></returns> |
11984 | // TODO: Convert old handler to use new method | ||
11985 | /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | ||
11986 | { | ||
11987 | AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; | ||
11988 | |||
11989 | if (cachedtex.AgentData.SessionID != SessionId) | ||
11990 | return false; | ||
11991 | |||
11992 | |||
11993 | List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>(); | ||
11994 | |||
11995 | for (int i = 0; i < cachedtex.WearableData.Length; i++) | ||
11996 | { | ||
11997 | CachedTextureRequestArg arg = new CachedTextureRequestArg(); | ||
11998 | arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex; | ||
11999 | arg.WearableHashID = cachedtex.WearableData[i].ID; | ||
12000 | |||
12001 | requestArgs.Add(arg); | ||
12002 | } | ||
12003 | |||
12004 | CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; | ||
12005 | if (handlerCachedTextureRequest != null) | ||
12006 | { | ||
12007 | handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); | ||
12008 | } | ||
12009 | |||
12010 | return true; | ||
12011 | }*/ | ||
12012 | |||
11744 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | 12013 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) |
11745 | { | 12014 | { |
11746 | //m_log.Debug("texture cached: " + packet.ToString()); | 12015 | //m_log.Debug("texture cached: " + packet.ToString()); |
@@ -11749,156 +12018,105 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11749 | 12018 | ||
11750 | if (cachedtex.AgentData.SessionID != SessionId) | 12019 | if (cachedtex.AgentData.SessionID != SessionId) |
11751 | return false; | 12020 | return false; |
11752 | |||
11753 | 12021 | ||
11754 | // TODO: don't create new blocks if recycling an old packet | 12022 | // TODO: don't create new blocks if recycling an old packet |
11755 | cachedresp.AgentData.AgentID = AgentId; | 12023 | cachedresp.AgentData.AgentID = AgentId; |
11756 | cachedresp.AgentData.SessionID = m_sessionId; | 12024 | cachedresp.AgentData.SessionID = m_sessionId; |
11757 | cachedresp.AgentData.SerialNum = m_cachedTextureSerial; | 12025 | cachedresp.AgentData.SerialNum = cachedtex.AgentData.SerialNum; |
11758 | m_cachedTextureSerial++; | ||
11759 | cachedresp.WearableData = | 12026 | cachedresp.WearableData = |
11760 | new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; | 12027 | new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; |
11761 | 12028 | ||
11762 | //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>(); | ||
11763 | // var item = fac.GetBakedTextureFaces(AgentId); | ||
11764 | //WearableCacheItem[] items = fac.GetCachedItems(AgentId); | ||
11765 | |||
11766 | IAssetService cache = m_scene.AssetService; | ||
11767 | IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>(); | ||
11768 | //bakedTextureModule = null; | ||
11769 | int maxWearablesLoop = cachedtex.WearableData.Length; | 12029 | int maxWearablesLoop = cachedtex.WearableData.Length; |
11770 | if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES) | 12030 | if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES) |
11771 | maxWearablesLoop = AvatarWearable.MAX_WEARABLES; | 12031 | maxWearablesLoop = AvatarWearable.MAX_WEARABLES; |
11772 | 12032 | ||
11773 | if (bakedTextureModule != null && cache != null) | 12033 | int cacheHits = 0; |
11774 | { | ||
11775 | // We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid | ||
11776 | 12034 | ||
11777 | WearableCacheItem[] cacheItems = null; | 12035 | // We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid |
11778 | ScenePresence p = m_scene.GetScenePresence(AgentId); | ||
11779 | if (p.Appearance != null) | ||
11780 | if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty) | ||
11781 | { | ||
11782 | try | ||
11783 | { | ||
11784 | cacheItems = bakedTextureModule.Get(AgentId); | ||
11785 | p.Appearance.WearableCacheItems = cacheItems; | ||
11786 | p.Appearance.WearableCacheItemsDirty = false; | ||
11787 | } | ||
11788 | 12036 | ||
11789 | /* | 12037 | WearableCacheItem[] cacheItems = null; |
11790 | * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception! | ||
11791 | * | ||
11792 | catch (System.Net.Sockets.SocketException) | ||
11793 | { | ||
11794 | cacheItems = null; | ||
11795 | } | ||
11796 | catch (WebException) | ||
11797 | { | ||
11798 | cacheItems = null; | ||
11799 | } | ||
11800 | catch (InvalidOperationException) | ||
11801 | { | ||
11802 | cacheItems = null; | ||
11803 | } */ | ||
11804 | catch (Exception) | ||
11805 | { | ||
11806 | cacheItems = null; | ||
11807 | } | ||
11808 | |||
11809 | } | ||
11810 | else if (p.Appearance.WearableCacheItems != null) | ||
11811 | { | ||
11812 | cacheItems = p.Appearance.WearableCacheItems; | ||
11813 | } | ||
11814 | 12038 | ||
11815 | if (cache != null && cacheItems != null) | 12039 | ScenePresence p = m_scene.GetScenePresence(AgentId); |
11816 | { | ||
11817 | foreach (WearableCacheItem item in cacheItems) | ||
11818 | { | ||
11819 | |||
11820 | if (cache.GetCached(item.TextureID.ToString()) == null) | ||
11821 | { | ||
11822 | item.TextureAsset.Temporary = true; | ||
11823 | cache.Store(item.TextureAsset); | ||
11824 | } | ||
11825 | 12040 | ||
12041 | if (p != null && p.Appearance != null) | ||
12042 | { | ||
12043 | cacheItems = p.Appearance.WearableCacheItems; | ||
12044 | } | ||
11826 | 12045 | ||
11827 | } | 12046 | if (cacheItems != null) |
11828 | } | 12047 | { |
11829 | 12048 | for (int i = 0; i < maxWearablesLoop; i++) | |
11830 | if (cacheItems != null) | ||
11831 | { | 12049 | { |
11832 | 12050 | int idx = cachedtex.WearableData[i].TextureIndex; | |
11833 | for (int i = 0; i < maxWearablesLoop; i++) | ||
11834 | { | ||
11835 | WearableCacheItem item = | ||
11836 | WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems); | ||
11837 | 12051 | ||
11838 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | 12052 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); |
11839 | cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex; | 12053 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; |
11840 | cachedresp.WearableData[i].HostName = new byte[0]; | 12054 | cachedresp.WearableData[i].HostName = new byte[0]; |
11841 | if (item != null && cachedtex.WearableData[i].ID == item.CacheId) | 12055 | if (cachedtex.WearableData[i].ID == cacheItems[idx].CacheId) |
11842 | { | 12056 | { |
11843 | 12057 | cachedresp.WearableData[i].TextureID = cacheItems[idx].TextureID; | |
11844 | cachedresp.WearableData[i].TextureID = item.TextureID; | 12058 | cacheHits++; |
11845 | } | ||
11846 | else | ||
11847 | { | ||
11848 | cachedresp.WearableData[i].TextureID = UUID.Zero; | ||
11849 | } | ||
11850 | } | 12059 | } |
11851 | } | 12060 | else |
11852 | else | ||
11853 | { | ||
11854 | for (int i = 0; i < maxWearablesLoop; i++) | ||
11855 | { | 12061 | { |
11856 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | ||
11857 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; | ||
11858 | cachedresp.WearableData[i].TextureID = UUID.Zero; | 12062 | cachedresp.WearableData[i].TextureID = UUID.Zero; |
11859 | //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46"); | ||
11860 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
11861 | } | 12063 | } |
11862 | } | 12064 | } |
11863 | } | 12065 | } |
11864 | else | 12066 | else |
11865 | { | 12067 | { |
11866 | if (cache == null) | 12068 | for (int i = 0; i < maxWearablesLoop; i++) |
11867 | { | 12069 | { |
11868 | for (int i = 0; i < maxWearablesLoop; i++) | 12070 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); |
11869 | { | 12071 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; |
11870 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | 12072 | cachedresp.WearableData[i].TextureID = UUID.Zero; |
11871 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; | 12073 | //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46"); |
11872 | cachedresp.WearableData[i].TextureID = UUID.Zero; | 12074 | cachedresp.WearableData[i].HostName = new byte[0]; |
11873 | //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46"); | ||
11874 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
11875 | } | ||
11876 | } | 12075 | } |
11877 | else | 12076 | } |
11878 | { | ||
11879 | for (int i = 0; i < maxWearablesLoop; i++) | ||
11880 | { | ||
11881 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | ||
11882 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; | ||
11883 | |||
11884 | 12077 | ||
12078 | m_log.DebugFormat("texture cached: hits {0}", cacheHits); | ||
11885 | 12079 | ||
11886 | if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null) | ||
11887 | cachedresp.WearableData[i].TextureID = UUID.Zero; | ||
11888 | //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46"); | ||
11889 | else | ||
11890 | cachedresp.WearableData[i].TextureID = UUID.Zero; | ||
11891 | // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46"); | ||
11892 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
11893 | } | ||
11894 | } | ||
11895 | } | ||
11896 | cachedresp.Header.Zerocoded = true; | 12080 | cachedresp.Header.Zerocoded = true; |
11897 | OutPacket(cachedresp, ThrottleOutPacketType.Task); | 12081 | OutPacket(cachedresp, ThrottleOutPacketType.Task); |
11898 | 12082 | ||
11899 | return true; | 12083 | return true; |
11900 | } | 12084 | } |
11901 | 12085 | ||
12086 | /// <summary> | ||
12087 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | ||
12088 | /// its appearance texture cached. | ||
12089 | /// </summary> | ||
12090 | /// <param name="avatar"></param> | ||
12091 | /// <param name="serial"></param> | ||
12092 | /// <param name="cachedTextures"></param> | ||
12093 | /// <returns></returns> | ||
12094 | public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures) | ||
12095 | { | ||
12096 | ScenePresence presence = avatar as ScenePresence; | ||
12097 | if (presence == null) | ||
12098 | return; | ||
12099 | |||
12100 | AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); | ||
12101 | |||
12102 | // TODO: don't create new blocks if recycling an old packet | ||
12103 | cachedresp.AgentData.AgentID = m_agentId; | ||
12104 | cachedresp.AgentData.SessionID = m_sessionId; | ||
12105 | cachedresp.AgentData.SerialNum = serial; | ||
12106 | cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count]; | ||
12107 | |||
12108 | for (int i = 0; i < cachedTextures.Count; i++) | ||
12109 | { | ||
12110 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | ||
12111 | cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex; | ||
12112 | cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID; | ||
12113 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
12114 | } | ||
12115 | |||
12116 | cachedresp.Header.Zerocoded = true; | ||
12117 | OutPacket(cachedresp, ThrottleOutPacketType.Task); | ||
12118 | } | ||
12119 | |||
11902 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) | 12120 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) |
11903 | { | 12121 | { |
11904 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; | 12122 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; |
@@ -11924,8 +12142,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11924 | if (part == null) | 12142 | if (part == null) |
11925 | { | 12143 | { |
11926 | // It's a ghost! tell the client to delete it from view. | 12144 | // It's a ghost! tell the client to delete it from view. |
11927 | simClient.SendKillObject(Scene.RegionInfo.RegionHandle, | 12145 | simClient.SendKillObject(new List<uint> { localId }); |
11928 | new List<uint> { localId }); | ||
11929 | } | 12146 | } |
11930 | else | 12147 | else |
11931 | { | 12148 | { |
@@ -12129,7 +12346,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12129 | /// <param name="throttles"></param> | 12346 | /// <param name="throttles"></param> |
12130 | public void SetChildAgentThrottle(byte[] throttles) | 12347 | public void SetChildAgentThrottle(byte[] throttles) |
12131 | { | 12348 | { |
12132 | m_udpClient.SetThrottles(throttles); | 12349 | SetChildAgentThrottle(throttles, 1.0f); |
12350 | } | ||
12351 | |||
12352 | public void SetChildAgentThrottle(byte[] throttles,float factor) | ||
12353 | { | ||
12354 | m_udpClient.SetThrottles(throttles, factor); | ||
12133 | GenericCall2 handler = OnUpdateThrottles; | 12355 | GenericCall2 handler = OnUpdateThrottles; |
12134 | if (handler != null) | 12356 | if (handler != null) |
12135 | { | 12357 | { |
@@ -12138,16 +12360,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12138 | } | 12360 | } |
12139 | 12361 | ||
12140 | /// <summary> | 12362 | /// <summary> |
12141 | /// Sets the throttles from values supplied by the client | 12363 | /// Sets the throttles from values supplied caller |
12142 | /// </summary> | 12364 | /// </summary> |
12143 | /// <param name="throttles"></param> | 12365 | /// <param name="throttles"></param> |
12144 | public void SetAgentThrottleSilent(int throttle, int setting) | 12366 | public void SetAgentThrottleSilent(int throttle, int setting) |
12145 | { | 12367 | { |
12146 | m_udpClient.ForceThrottleSetting(throttle,setting); | 12368 | m_udpClient.ForceThrottleSetting(throttle,setting); |
12147 | //m_udpClient.SetThrottles(throttles); | ||
12148 | |||
12149 | } | 12369 | } |
12150 | 12370 | ||
12371 | public int GetAgentThrottleSilent(int throttle) | ||
12372 | { | ||
12373 | return m_udpClient.GetThrottleSetting(throttle); | ||
12374 | } | ||
12151 | 12375 | ||
12152 | /// <summary> | 12376 | /// <summary> |
12153 | /// Get the current throttles for this client as a packed byte array | 12377 | /// Get the current throttles for this client as a packed byte array |
@@ -12250,8 +12474,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12250 | uint regionY = 0; | 12474 | uint regionY = 0; |
12251 | 12475 | ||
12252 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY); | 12476 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY); |
12253 | locx = Convert.ToSingle(args[0]) - (float)regionX; | 12477 | locx = (float)(Convert.ToDouble(args[0]) - (double)regionX); |
12254 | locy = Convert.ToSingle(args[1]) - (float)regionY; | 12478 | locy = (float)(Convert.ToDouble(args[1]) - (double)regionY); |
12255 | locz = Convert.ToSingle(args[2]); | 12479 | locz = Convert.ToSingle(args[2]); |
12256 | 12480 | ||
12257 | Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo; | 12481 | Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo; |
@@ -12299,6 +12523,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12299 | 12523 | ||
12300 | shape.PCode = addPacket.ObjectData.PCode; | 12524 | shape.PCode = addPacket.ObjectData.PCode; |
12301 | shape.State = addPacket.ObjectData.State; | 12525 | shape.State = addPacket.ObjectData.State; |
12526 | shape.LastAttachPoint = addPacket.ObjectData.State; | ||
12302 | shape.PathBegin = addPacket.ObjectData.PathBegin; | 12527 | shape.PathBegin = addPacket.ObjectData.PathBegin; |
12303 | shape.PathEnd = addPacket.ObjectData.PathEnd; | 12528 | shape.PathEnd = addPacket.ObjectData.PathEnd; |
12304 | shape.PathScaleX = addPacket.ObjectData.PathScaleX; | 12529 | shape.PathScaleX = addPacket.ObjectData.PathScaleX; |
@@ -12329,7 +12554,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12329 | ClientInfo info = m_udpClient.GetClientInfo(); | 12554 | ClientInfo info = m_udpClient.GetClientInfo(); |
12330 | 12555 | ||
12331 | info.proxyEP = null; | 12556 | info.proxyEP = null; |
12332 | info.agentcircuit = RequestClientInfo(); | 12557 | if (info.agentcircuit == null) |
12558 | info.agentcircuit = RequestClientInfo(); | ||
12333 | 12559 | ||
12334 | return info; | 12560 | return info; |
12335 | } | 12561 | } |
@@ -12712,11 +12938,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12712 | OutPacket(dialog, ThrottleOutPacketType.Task); | 12938 | OutPacket(dialog, ThrottleOutPacketType.Task); |
12713 | } | 12939 | } |
12714 | 12940 | ||
12715 | public void StopFlying(ISceneEntity p) | 12941 | public void SendAgentTerseUpdate(ISceneEntity p) |
12716 | { | 12942 | { |
12717 | if (p is ScenePresence) | 12943 | if (p is ScenePresence) |
12718 | { | 12944 | { |
12719 | ScenePresence presence = p as ScenePresence; | 12945 | // m_log.DebugFormat( |
12946 | // "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}", | ||
12947 | // p.Name, Name, Scene.Name); | ||
12948 | |||
12720 | // It turns out to get the agent to stop flying, you have to feed it stop flying velocities | 12949 | // It turns out to get the agent to stop flying, you have to feed it stop flying velocities |
12721 | // There's no explicit message to send the client to tell it to stop flying.. it relies on the | 12950 | // There's no explicit message to send the client to tell it to stop flying.. it relies on the |
12722 | // velocity, collision plane and avatar height | 12951 | // velocity, collision plane and avatar height |
@@ -12724,34 +12953,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12724 | // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air | 12953 | // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air |
12725 | // when the avatar stands up | 12954 | // when the avatar stands up |
12726 | 12955 | ||
12727 | Vector3 pos = presence.AbsolutePosition; | ||
12728 | |||
12729 | if (presence.Appearance.AvatarHeight != 127.0f) | ||
12730 | pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f)); | ||
12731 | else | ||
12732 | pos += new Vector3(0f, 0f, (1.56f/6f)); | ||
12733 | |||
12734 | presence.AbsolutePosition = pos; | ||
12735 | |||
12736 | // attach a suitable collision plane regardless of the actual situation to force the LLClient to land. | ||
12737 | // Collision plane below the avatar's position a 6th of the avatar's height is suitable. | ||
12738 | // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a | ||
12739 | // certain amount.. because the LLClient wouldn't land in that situation anyway. | ||
12740 | |||
12741 | // why are we still testing for this really old height value default??? | ||
12742 | if (presence.Appearance.AvatarHeight != 127.0f) | ||
12743 | presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f); | ||
12744 | else | ||
12745 | presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f)); | ||
12746 | |||
12747 | |||
12748 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = | 12956 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = |
12749 | CreateImprovedTerseBlock(p, false); | 12957 | CreateImprovedTerseBlock(p, false); |
12750 | 12958 | ||
12751 | const float TIME_DILATION = 1.0f; | 12959 | const float TIME_DILATION = 1.0f; |
12752 | ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); | 12960 | ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); |
12753 | 12961 | ||
12754 | |||
12755 | ImprovedTerseObjectUpdatePacket packet | 12962 | ImprovedTerseObjectUpdatePacket packet |
12756 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( | 12963 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( |
12757 | PacketType.ImprovedTerseObjectUpdate); | 12964 | PacketType.ImprovedTerseObjectUpdate); |