From 7276a89ddd818c4bd0611345e8af1813f2843184 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 7 Sep 2015 11:23:00 +0100 Subject: recover opensim m_sendTerrainUpdatesByViewDistance. if false do as opensim (slower since it depended on sending terrain as TASK). if true send by view range and also all terrain at arrival --- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 47 ++++- .../CoreModules/World/Terrain/TerrainModule.cs | 198 ++++++++++++++++----- 2 files changed, 189 insertions(+), 56 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 6df55a6..7c5aee7 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -1242,14 +1242,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP try { // Send LayerData in typerwriter pattern + //for (int y = 0; y < 16; y++) + //{ + // for (int x = 0; x < 16; x++) + // { + // SendLayerData(x, y, map); + // } + //} - for (int y = 0; y < 16; y++) - { - for (int x = 0; x < 16; x++) - { - SendLayerData(x, y, map); - } - } + // Send LayerData in a spiral pattern. Fun! + SendLayerTopRight(map, 0, 0, map.SizeX / Constants.TerrainPatchSize - 1, map.SizeY / Constants.TerrainPatchSize - 1); } catch (Exception e) { @@ -1257,6 +1259,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + private void SendLayerTopRight(TerrainData map, int x1, int y1, int x2, int y2) + { + // Row + for (int i = x1; i <= x2; i++) + SendLayerData(i, y1, map); + + // Column + for (int j = y1 + 1; j <= y2; j++) + SendLayerData(x2, j, map); + + if (x2 - x1 > 0 && y2 - y1 > 0) + SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2); + } + + void SendLayerBottomLeft(TerrainData map, int x1, int y1, int x2, int y2) + { + // Row in reverse + for (int i = x2; i >= x1; i--) + SendLayerData(i, y2, map); + + // Column in reverse + for (int j = y2 - 1; j >= y1; j--) + SendLayerData(x1, j, map); + + if (x2 - x1 > 0 && y2 - y1 > 0) + SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1); + } + + // Legacy form of invocation that passes around a bare data array. // Just ignore what was passed and use the real terrain info that is part of the scene. // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI, @@ -1359,7 +1390,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void SendTheLayerPacket(LayerDataPacket layerpack) { - OutPacket(layerpack, ThrottleOutPacketType.Land); + OutPacket(layerpack, ThrottleOutPacketType.Land); } /// diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index e3a0825..2f4618d 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -107,6 +107,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain private bool[,] updated; // for each patch, whether it needs to be sent to this client private int updateCount; // number of patches that need to be sent public ScenePresence Presence; // a reference to the client to send to + public bool sendAll; + public int sendAllcurrentX; + public int sendAllcurrentY; + public PatchUpdates(TerrainData terrData, ScenePresence pPresence) { @@ -150,6 +154,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain updated[xx, yy] = state; if (state) updateCount = updated.GetLength(0) * updated.GetLength(1); + sendAllcurrentX = 0; + sendAllcurrentY = 0; + sendAll = true; } // Logically OR's the terrain data's patch taint map into this client's update map. @@ -211,7 +218,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (terrainConfig != null) { m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); - m_sendTerrainUpdatesByViewDistance = terrainConfig.GetBoolean("SendTerrainUpdatesByViewDistance", m_sendTerrainUpdatesByViewDistance); + m_sendTerrainUpdatesByViewDistance = + terrainConfig.GetBoolean( + "SendTerrainUpdatesByViewDistance",m_sendTerrainUpdatesByViewDistance); } } @@ -524,21 +533,29 @@ namespace OpenSim.Region.CoreModules.World.Terrain // ITerrainModule.PushTerrain() public void PushTerrain(IClientAPI pClient) { - ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); - if (presence != null) + if (m_sendTerrainUpdatesByViewDistance) { - lock (m_perClientPatchUpdates) + ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); + if (presence != null) { - PatchUpdates pups; - if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) + lock (m_perClientPatchUpdates) { - // There is a ScenePresence without a send patch map. Create one. - pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence); - m_perClientPatchUpdates.Add(presence.UUID, pups); + PatchUpdates pups; + if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) + { + // There is a ScenePresence without a send patch map. Create one. + pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence); + m_perClientPatchUpdates.Add(presence.UUID, pups); + } + pups.SetAll(true); } - pups.SetAll(true); } } + else + { + // The traditional way is to call into the protocol stack to send them all. + pClient.SendLayerData(new float[10]); + } } #region Plugin Loading Methods @@ -949,19 +966,37 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// The patch corner to send private void SendToClients(TerrainData terrData, int x, int y) { - // Add that this patch needs to be sent to the accounting for each client. - lock (m_perClientPatchUpdates) + if (m_sendTerrainUpdatesByViewDistance) { - m_scene.ForEachScenePresence(presence => - { - PatchUpdates thisClientUpdates; - if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) + // Add that this patch needs to be sent to the accounting for each client. + lock (m_perClientPatchUpdates) + { + m_scene.ForEachScenePresence(presence => { - // There is a ScenePresence without a send patch map. Create one. - thisClientUpdates = new PatchUpdates(terrData, presence); - m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); + PatchUpdates thisClientUpdates; + if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) + { + // There is a ScenePresence without a send patch map. Create one. + thisClientUpdates = new PatchUpdates(terrData, presence); + m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); + } + thisClientUpdates.SetByXY(x, y, true); } - thisClientUpdates.SetByXY(x, y, true); + ); + } + } + else + { + // Legacy update sending where the update is sent out as soon as noticed + // We know the actual terrain data that is passed is ignored so this passes a dummy heightmap. + //float[] heightMap = terrData.GetFloatsSerialized(); + float[] heightMap = new float[10]; + m_scene.ForEachClient( + delegate (IClientAPI controller) + { + controller.SendLayerData(x / Constants.TerrainPatchSize, + y / Constants.TerrainPatchSize, + heightMap); } ); } @@ -993,46 +1028,113 @@ namespace OpenSim.Region.CoreModules.World.Terrain { foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) { - if (!Monitor.TryEnter(pups)) - continue; - // throught acording to land queue free to send bytes if (!pups.Presence.ControllingClient.CanSendLayerData()) continue; if (pups.HasUpdates()) { - - // There is something that could be sent to this client. - List toSend = GetModifiedPatchesInViewDistance(pups); - if (toSend.Count > 0) + if (m_sendTerrainUpdatesByViewDistance) { - // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}", - // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); - // Sort the patches to send by the distance from the presence - toSend.Sort(); - /* - foreach (PatchesToSend pts in toSend) + // There is something that could be sent to this client. + List toSend = GetModifiedPatchesInViewDistance(pups); + if (toSend.Count > 0) { - pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null); - // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land); + // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}", + // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); + // Sort the patches to send by the distance from the presence + toSend.Sort(); + /* + foreach (PatchesToSend pts in toSend) + { + pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null); + // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land); + } + */ + + int[] xPieces = new int[toSend.Count]; + int[] yPieces = new int[toSend.Count]; + float[] patchPieces = new float[toSend.Count * 2]; + int pieceIndex = 0; + foreach (PatchesToSend pts in toSend) + { + patchPieces[pieceIndex++] = pts.PatchX; + patchPieces[pieceIndex++] = pts.PatchY; + } + pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces); } - */ + if (pups.sendAll && toSend.Count < 1024) + SendAllModifiedPatchs(pups); + } + else + SendAllModifiedPatchs(pups); + } + } + } + } + private void SendAllModifiedPatchs(PatchUpdates pups) + { + if (!pups.sendAll) // sanity + return; - int[] xPieces = new int[toSend.Count]; - int[] yPieces = new int[toSend.Count]; - float[] patchPieces = new float[toSend.Count * 2]; - int pieceIndex = 0; - foreach (PatchesToSend pts in toSend) - { - patchPieces[pieceIndex++] = pts.PatchX; - patchPieces[pieceIndex++] = pts.PatchY; - } - pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces); + int limitX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize; + int limitY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize; + + if (pups.sendAllcurrentX > limitX || pups.sendAllcurrentY > limitY) + { + pups.sendAll = false; + pups.sendAllcurrentX = 0; + pups.sendAllcurrentY = 0; + return; + } + + int npatchs = 0; + List patchs = new List(); + int x = pups.sendAllcurrentX; + int y = pups.sendAllcurrentY; + // send it in the order viewer draws it + // even if not best for memory scan + for (; y < limitY; y++) + { + for (; x < limitX; x++) + { + if (pups.GetByPatch(x, y)) + { + pups.SetByPatch(x, y, false); + patchs.Add(new PatchesToSend(x, y, 0)); + if (++npatchs >= 512) + { + pups.sendAllcurrentX = x + 1; + pups.sendAllcurrentY = y; + break; } } - Monitor.Exit(pups); } + if (npatchs >= 512) + break; + x = 0; + } + + if (x >= limitX && y >= limitY) + { + pups.sendAll = false; + pups.sendAllcurrentX = 0; + pups.sendAllcurrentY = 0; + } + + npatchs = patchs.Count; + if (npatchs > 0) + { + int[] xPieces = new int[npatchs]; + int[] yPieces = new int[npatchs]; + float[] patchPieces = new float[npatchs * 2]; + int pieceIndex = 0; + foreach (PatchesToSend pts in patchs) + { + patchPieces[pieceIndex++] = pts.PatchX; + patchPieces[pieceIndex++] = pts.PatchY; + } + pups.Presence.ControllingClient.SendLayerData(-npatchs, 0, patchPieces); } } @@ -1119,7 +1221,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain { pups.SetByPatch(x, y, false); ret.Add(new PatchesToSend(x, y, (float)distsq)); - if (npatchs++ > 65536) + if (npatchs++ > 1024) { y = endY; x = endX; -- cgit v1.1