From 6535f23e4b8fec9578dae5275db69b237a99e498 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sat, 7 Jul 2012 02:05:01 +0200 Subject: Add saving vehicle physics data to the database --- OpenSim/Region/Framework/Scenes/SOPVehicle.cs | 33 +++++++++++++++++- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 40 +++++++++++----------- .../Scenes/Serialization/SceneObjectSerializer.cs | 8 ++--- 3 files changed, 56 insertions(+), 25 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/SOPVehicle.cs b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs index d3c2d27..45ca00c 100644 --- a/OpenSim/Region/Framework/Scenes/SOPVehicle.cs +++ b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs @@ -30,6 +30,8 @@ using System.Collections.Generic; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Physics.Manager; +using System.Text; +using System.IO; using System.Xml; using OpenSim.Framework.Serialization; using OpenSim.Framework.Serialization.External; @@ -561,6 +563,35 @@ namespace OpenSim.Region.Framework.Scenes } + public string ToXml2() + { + MemoryStream ms = new MemoryStream(); + UTF8Encoding enc = new UTF8Encoding(); + XmlTextWriter writer = new XmlTextWriter(ms, null); + ToXml2(writer); + return enc.GetString(ms.ToArray()); + } + + public static SOPVehicle FromXml2(string text) + { + if (text == String.Empty) + return null; + UTF8Encoding enc = new UTF8Encoding(); + MemoryStream ms = new MemoryStream(enc.GetBytes(text)); + XmlTextReader reader = new XmlTextReader(ms); + + SOPVehicle v = new SOPVehicle(); + bool error; + + v.FromXml2(reader, out error); + if (error) + { + v = null; + return null; + } + + return v; + } public void FromXml2(XmlTextReader _reader, out bool errors) { @@ -739,4 +770,4 @@ namespace OpenSim.Region.Framework.Scenes vd.m_referenceFrame = XRquat(); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index ed32adc..dd30a59 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -338,7 +338,7 @@ namespace OpenSim.Region.Framework.Scenes private int LastColSoundSentTime; - private SOPVehicle m_vehicle = null; + private SOPVehicle m_vehicleParams = null; private KeyframeMotion m_keyframeMotion = null; @@ -3379,15 +3379,15 @@ namespace OpenSim.Region.Framework.Scenes Force = force; } - public SOPVehicle sopVehicle + public SOPVehicle VehicleParams { get { - return m_vehicle; + return m_vehicleParams; } set { - m_vehicle = value; + m_vehicleParams = value; } } @@ -3396,10 +3396,10 @@ namespace OpenSim.Region.Framework.Scenes { get { - if (m_vehicle == null) + if (m_vehicleParams == null) return (int)Vehicle.TYPE_NONE; else - return (int)m_vehicle.Type; + return (int)m_vehicleParams.Type; } set { @@ -3409,7 +3409,7 @@ namespace OpenSim.Region.Framework.Scenes public void SetVehicleType(int type) { - m_vehicle = null; + m_vehicleParams = null; if (type == (int)Vehicle.TYPE_NONE) { @@ -3417,8 +3417,8 @@ namespace OpenSim.Region.Framework.Scenes PhysActor.VehicleType = (int)Vehicle.TYPE_NONE; return; } - m_vehicle = new SOPVehicle(); - m_vehicle.ProcessTypeChange((Vehicle)type); + m_vehicleParams = new SOPVehicle(); + m_vehicleParams.ProcessTypeChange((Vehicle)type); { if (_parentID ==0 && PhysActor != null) PhysActor.VehicleType = type; @@ -3428,10 +3428,10 @@ namespace OpenSim.Region.Framework.Scenes public void SetVehicleFlags(int param, bool remove) { - if (m_vehicle == null) + if (m_vehicleParams == null) return; - m_vehicle.ProcessVehicleFlags(param, remove); + m_vehicleParams.ProcessVehicleFlags(param, remove); if (_parentID ==0 && PhysActor != null) { @@ -3441,10 +3441,10 @@ namespace OpenSim.Region.Framework.Scenes public void SetVehicleFloatParam(int param, float value) { - if (m_vehicle == null) + if (m_vehicleParams == null) return; - m_vehicle.ProcessFloatVehicleParam((Vehicle)param, value); + m_vehicleParams.ProcessFloatVehicleParam((Vehicle)param, value); if (_parentID == 0 && PhysActor != null) { @@ -3454,10 +3454,10 @@ namespace OpenSim.Region.Framework.Scenes public void SetVehicleVectorParam(int param, Vector3 value) { - if (m_vehicle == null) + if (m_vehicleParams == null) return; - m_vehicle.ProcessVectorVehicleParam((Vehicle)param, value); + m_vehicleParams.ProcessVectorVehicleParam((Vehicle)param, value); if (_parentID == 0 && PhysActor != null) { @@ -3467,10 +3467,10 @@ namespace OpenSim.Region.Framework.Scenes public void SetVehicleRotationParam(int param, Quaternion rotation) { - if (m_vehicle == null) + if (m_vehicleParams == null) return; - m_vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); + m_vehicleParams.ProcessRotationVehicleParam((Vehicle)param, rotation); if (_parentID == 0 && PhysActor != null) { @@ -4637,8 +4637,8 @@ namespace OpenSim.Region.Framework.Scenes if (VolumeDetectActive) // change if not the default only pa.SetVolumeDetect(1); - if (m_vehicle != null && LocalId == ParentGroup.RootPart.LocalId) - m_vehicle.SetVehicle(pa); + if (m_vehicleParams != null && LocalId == ParentGroup.RootPart.LocalId) + m_vehicleParams.SetVehicle(pa); // we are going to tell rest of code about physics so better have this here PhysActor = pa; @@ -4676,7 +4676,7 @@ namespace OpenSim.Region.Framework.Scenes pa.RotationalVelocity = rotationalVelocity; // if not vehicle and root part apply force and torque - if ((m_vehicle == null || m_vehicle.Type == Vehicle.TYPE_NONE) + if ((m_vehicleParams == null || m_vehicleParams.Type == Vehicle.TYPE_NONE) && LocalId == ParentGroup.RootPart.LocalId) { pa.Force = Force; diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 151eba2..c7e4c3e 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -630,13 +630,13 @@ namespace OpenSim.Region.Framework.Scenes.Serialization if (errors) { - obj.sopVehicle = null; + obj.VehicleParams = null; m_log.DebugFormat( "[SceneObjectSerializer]: Parsing Vehicle for object part {0} {1} encountered errors. Please see earlier log entries.", obj.Name, obj.UUID); } else - obj.sopVehicle = _vehicle; + obj.VehicleParams = _vehicle; } private static void ProcessShape(SceneObjectPart obj, XmlTextReader reader) @@ -1325,8 +1325,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString("VolumeDetectActive", sop.VolumeDetectActive.ToString().ToLower()); - if (sop.sopVehicle != null) - sop.sopVehicle.ToXml2(writer); + if (sop.VehicleParams != null) + sop.VehicleParams.ToXml2(writer); if(sop.PhysicsShapeType != sop.DefaultPhysicsShapeType()) writer.WriteElementString("PhysicsShapeType", sop.PhysicsShapeType.ToString().ToLower()); -- cgit v1.1 From d50b852d530bd17f2bb5a7964e9ddf81acff9146 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 7 Jul 2012 03:16:41 +0100 Subject: ODE turn off material dependent friction while vehicle linear motor is Effective. Increase a bit world damping of velocities --- OpenSim/Region/Physics/UbitOdePlugin/ODEDynamics.cs | 9 ++++++--- OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs | 1 + OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEDynamics.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEDynamics.cs index e27be1e..e900c02 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODEDynamics.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEDynamics.cs @@ -137,6 +137,7 @@ namespace OpenSim.Region.Physics.OdePlugin float m_amdampY; float m_amdampZ; + public float FrictionFactor { get @@ -145,6 +146,7 @@ namespace OpenSim.Region.Physics.OdePlugin } } + public ODEDynamics(OdePrim rootp) { rootPrim = rootp; @@ -345,7 +347,7 @@ namespace OpenSim.Region.Physics.OdePlugin m_lmDecay = 1.0f - 1.0f / m_linearMotorDecayTimescale; m_lmEfect = 1.0f; // turn it on - m_ffactor = 0.01f; + m_ffactor = 0.0f; if (rootPrim.Body != IntPtr.Zero && !d.BodyIsEnabled(rootPrim.Body) && !rootPrim.m_isSelected && !rootPrim.m_disabled) d.BodyEnable(rootPrim.Body); @@ -401,7 +403,7 @@ namespace OpenSim.Region.Physics.OdePlugin m_lmEfect = 1.0f; // turn it on m_lmDecay = 1.0f - 1.0f / m_linearMotorDecayTimescale; - m_ffactor = 0.01f; + m_ffactor = 0.0f; if (rootPrim.Body != IntPtr.Zero && !d.BodyIsEnabled(rootPrim.Body) && !rootPrim.m_isSelected && !rootPrim.m_disabled) d.BodyEnable(rootPrim.Body); @@ -805,7 +807,8 @@ namespace OpenSim.Region.Physics.OdePlugin } m_lmEfect *= m_lmDecay; - m_ffactor = 0.01f + 1e-4f * curVel.LengthSquared(); +// m_ffactor = 0.01f + 1e-4f * curVel.LengthSquared(); + m_ffactor = 0.0f; } else { diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs index 9b3b51b..3d8e680 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs @@ -275,6 +275,7 @@ namespace OpenSim.Region.Physics.OdePlugin if (veh != null && veh.Type != Vehicle.TYPE_NONE) cdata.mu *= veh.FrictionFactor; +// cdata.mu *= 0; } } diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs index 6c72324..4552f3f 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs @@ -526,8 +526,8 @@ namespace OpenSim.Region.Physics.OdePlugin d.WorldSetGravity(world, gravityx, gravityy, gravityz); d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); - d.WorldSetLinearDamping(world, 0.001f); - d.WorldSetAngularDamping(world, 0.001f); + d.WorldSetLinearDamping(world, 0.002f); + d.WorldSetAngularDamping(world, 0.002f); d.WorldSetAngularDampingThreshold(world, 0f); d.WorldSetLinearDampingThreshold(world, 0f); d.WorldSetMaxAngularSpeed(world, 100f); -- cgit v1.1 From afa02aa104e0cfbedd0e1b6c1d7b60522a79a4e8 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Sat, 7 Jul 2012 07:41:11 +0100 Subject: fix vehicle to XML string --- OpenSim/Region/Framework/Scenes/SOPVehicle.cs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/SOPVehicle.cs b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs index 45ca00c..e2ef77b 100644 --- a/OpenSim/Region/Framework/Scenes/SOPVehicle.cs +++ b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs @@ -565,31 +565,37 @@ namespace OpenSim.Region.Framework.Scenes public string ToXml2() { - MemoryStream ms = new MemoryStream(); + MemoryStream ms = new MemoryStream(512); UTF8Encoding enc = new UTF8Encoding(); - XmlTextWriter writer = new XmlTextWriter(ms, null); - ToXml2(writer); - return enc.GetString(ms.ToArray()); + XmlTextWriter xwriter = new XmlTextWriter(ms, enc); + ToXml2(xwriter); + xwriter.Flush(); + string s = ms.GetStreamString(); + xwriter.Close(); + return s; } public static SOPVehicle FromXml2(string text) { if (text == String.Empty) return null; + UTF8Encoding enc = new UTF8Encoding(); MemoryStream ms = new MemoryStream(enc.GetBytes(text)); - XmlTextReader reader = new XmlTextReader(ms); + XmlTextReader xreader = new XmlTextReader(ms); SOPVehicle v = new SOPVehicle(); bool error; - v.FromXml2(reader, out error); + v.FromXml2(xreader, out error); + + xreader.Close(); + if (error) { v = null; return null; } - return v; } -- cgit v1.1 From 470019b52a72de1a8777933ce3254cde87e184f9 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sat, 7 Jul 2012 19:59:55 +0200 Subject: Change semantics of FromXML on vehicle data to make the serializer a bit cleaner --- OpenSim/Region/Framework/Scenes/SOPVehicle.cs | 15 ++++++++++++++- .../Scenes/Serialization/SceneObjectSerializer.cs | 11 +++++------ 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/SOPVehicle.cs b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs index e2ef77b..41e8944 100644 --- a/OpenSim/Region/Framework/Scenes/SOPVehicle.cs +++ b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs @@ -599,7 +599,20 @@ namespace OpenSim.Region.Framework.Scenes return v; } - public void FromXml2(XmlTextReader _reader, out bool errors) + public static SOPVehicle FromXml2(XmlTextReader reader) + { + SOPVehicle vehicle = new SOPVehicle(); + + bool errors = false; + + vehicle.FromXml2(reader, out errors); + if (errors) + return null; + + return vehicle; + } + + private void FromXml2(XmlTextReader _reader, out bool errors) { errors = false; reader = _reader; diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index c7e4c3e..abca14f 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -623,12 +623,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessVehicle(SceneObjectPart obj, XmlTextReader reader) { - bool errors = false; - SOPVehicle _vehicle = new SOPVehicle(); + SOPVehicle vehicle = SOPVehicle.FromXml2(reader); - _vehicle.FromXml2(reader, out errors); - - if (errors) + if (vehicle == null) { obj.VehicleParams = null; m_log.DebugFormat( @@ -636,7 +633,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization obj.Name, obj.UUID); } else - obj.VehicleParams = _vehicle; + { + obj.VehicleParams = vehicle; + } } private static void ProcessShape(SceneObjectPart obj, XmlTextReader reader) -- cgit v1.1 From d3b778ebbe617a37a32c866101c75284dad8f15a Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 8 Jul 2012 06:06:33 +0200 Subject: Address map lag issue seen with non-avination viewers --- .../CoreModules/World/WorldMap/MapSearchModule.cs | 161 +++++----- .../CoreModules/World/WorldMap/WorldMapModule.cs | 357 ++++++++++----------- 2 files changed, 257 insertions(+), 261 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index 4e6bfb8..2417b1a 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs @@ -86,90 +86,93 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) { - if (mapName.Length < 2) + Util.FireAndForget(x => { - remoteClient.SendAlertMessage("Use a search string with at least 2 characters"); - return; - } + if (mapName.Length < 2) + { + remoteClient.SendAlertMessage("Use a search string with at least 2 characters"); + return; + } - //m_log.DebugFormat("MAP NAME=({0})", mapName); - - // Hack to get around the fact that ll V3 now drops the port from the - // map name. See https://jira.secondlife.com/browse/VWR-28570 - // - // Caller, use this magic form instead: - // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 - // or url encode if possible. - // the hacks we do with this viewer... - // - string mapNameOrig = mapName; - if (mapName.Contains("|")) - mapName = mapName.Replace('|', ':'); - if (mapName.Contains("+")) - mapName = mapName.Replace('+', ' '); - if (mapName.Contains("!")) - mapName = mapName.Replace('!', '/'); - - // try to fetch from GridServer - List regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); -// if (regionInfos.Count == 0) -// remoteClient.SendAlertMessage("Hyperlink could not be established."); - - //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); - List blocks = new List(); - - MapBlockData data; - if (regionInfos.Count > 0) - { - foreach (GridRegion info in regionInfos) + //m_log.DebugFormat("MAP NAME=({0})", mapName); + + // Hack to get around the fact that ll V3 now drops the port from the + // map name. See https://jira.secondlife.com/browse/VWR-28570 + // + // Caller, use this magic form instead: + // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 + // or url encode if possible. + // the hacks we do with this viewer... + // + string mapNameOrig = mapName; + if (mapName.Contains("|")) + mapName = mapName.Replace('|', ':'); + if (mapName.Contains("+")) + mapName = mapName.Replace('+', ' '); + if (mapName.Contains("!")) + mapName = mapName.Replace('!', '/'); + + // try to fetch from GridServer + List regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); + // if (regionInfos.Count == 0) + // remoteClient.SendAlertMessage("Hyperlink could not be established."); + + //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); + List blocks = new List(); + + MapBlockData data; + if (regionInfos.Count > 0) { - data = new MapBlockData(); - data.Agents = 0; - data.Access = info.Access; - if (flags == 2) // V2 sends this - data.MapImageId = UUID.Zero; - else - data.MapImageId = info.TerrainImage; - // ugh! V2-3 is very sensitive about the result being - // exactly the same as the requested name - if (regionInfos.Count == 1 && mapNameOrig.Contains("|") || mapNameOrig.Contains("+")) - data.Name = mapNameOrig; - else - data.Name = info.RegionName; - data.RegionFlags = 0; // TODO not used? - data.WaterHeight = 0; // not used - data.X = (ushort)(info.RegionLocX / Constants.RegionSize); - data.Y = (ushort)(info.RegionLocY / Constants.RegionSize); - blocks.Add(data); + foreach (GridRegion info in regionInfos) + { + data = new MapBlockData(); + data.Agents = 0; + data.Access = info.Access; + if (flags == 2) // V2 sends this + data.MapImageId = UUID.Zero; + else + data.MapImageId = info.TerrainImage; + // ugh! V2-3 is very sensitive about the result being + // exactly the same as the requested name + if (regionInfos.Count == 1 && mapNameOrig.Contains("|") || mapNameOrig.Contains("+")) + data.Name = mapNameOrig; + else + data.Name = info.RegionName; + data.RegionFlags = 0; // TODO not used? + data.WaterHeight = 0; // not used + data.X = (ushort)(info.RegionLocX / Constants.RegionSize); + data.Y = (ushort)(info.RegionLocY / Constants.RegionSize); + blocks.Add(data); + } } - } - // final block, closing the search result - data = new MapBlockData(); - data.Agents = 0; - data.Access = 255; - data.MapImageId = UUID.Zero; - data.Name = mapName; - data.RegionFlags = 0; - data.WaterHeight = 0; // not used - data.X = 0; - data.Y = 0; - blocks.Add(data); - - // flags are agent flags sent from the viewer. - // they have different values depending on different viewers, apparently - remoteClient.SendMapBlock(blocks, flags); - - // send extra user messages for V3 - // because the UI is very confusing - // while we don't fix the hard-coded urls - if (flags == 2) - { - if (regionInfos.Count == 0) - remoteClient.SendAgentAlertMessage("No regions found with that name.", true); - else if (regionInfos.Count == 1) - remoteClient.SendAgentAlertMessage("Region found!", false); - } + // final block, closing the search result + data = new MapBlockData(); + data.Agents = 0; + data.Access = 255; + data.MapImageId = UUID.Zero; + data.Name = mapName; + data.RegionFlags = 0; + data.WaterHeight = 0; // not used + data.X = 0; + data.Y = 0; + blocks.Add(data); + + // flags are agent flags sent from the viewer. + // they have different values depending on different viewers, apparently + remoteClient.SendMapBlock(blocks, flags); + + // send extra user messages for V3 + // because the UI is very confusing + // while we don't fix the hard-coded urls + if (flags == 2) + { + if (regionInfos.Count == 0) + remoteClient.SendAgentAlertMessage("No regions found with that name.", true); + else if (regionInfos.Count == 1) + remoteClient.SendAgentAlertMessage("Region found!", false); + } + }); } // private Scene GetClientScene(IClientAPI client) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 899e5ea..721ac5c 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -63,7 +63,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private static readonly UUID STOP_UUID = UUID.Random(); private static readonly string m_mapLayerPath = "0001/"; - private OpenSim.Framework.BlockingQueue requests = new OpenSim.Framework.BlockingQueue(); + private ManualResetEvent queueEvent = new ManualResetEvent(false); + private Queue requests = new Queue(); protected Scene m_scene; private List cachedMapBlocks = new List(); @@ -71,7 +72,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private int blacklistTimeout = 10*60*1000; // 10 minutes private byte[] myMapImageJPEG; protected volatile bool m_Enabled = false; - private Dictionary m_openRequests = new Dictionary(); private Dictionary m_blacklistedurls = new Dictionary(); private Dictionary m_blacklistedregions = new Dictionary(); private Dictionary m_cachedRegionMapItemsAddress = new Dictionary(); @@ -368,7 +368,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap st.itemtype=0; st.regionhandle=0; - requests.Enqueue(st); + lock (requests) + { + queueEvent.Set(); + requests.Enqueue(st); + } } public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, @@ -519,12 +523,26 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// public void process() { - const int MAX_ASYNC_REQUESTS = 20; + const int MAX_ASYNC_REQUESTS = 5; try { while (true) { - MapRequestState st = requests.Dequeue(1000); + MapRequestState st = new MapRequestState(); + bool valid = false; + queueEvent.WaitOne(); + lock (requests) + { + if (requests.Count > 0) + { + st = requests.Dequeue(); + valid = true; + } + if (requests.Count == 0) + queueEvent.Reset(); + } + if (!valid) + continue; // end gracefully if (st.agentID == STOP_UUID) @@ -541,14 +559,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle)) { - while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break - Thread.Sleep(80); +// while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break +// Thread.Sleep(500); - RequestMapItemsDelegate d = RequestMapItemsAsync; - d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null); - //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); - //RequestMapItemsCompleted(response); Interlocked.Increment(ref nAsyncRequests); + RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); } } @@ -570,110 +585,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// public void EnqueueMapItemRequest(MapRequestState state) { - requests.Enqueue(state); - } - - /// - /// Sends the mapitem response to the IClientAPI - /// - /// The OSDMap Response for the mapitem - private void RequestMapItemsCompleted(IAsyncResult iar) - { - AsyncResult result = (AsyncResult)iar; - RequestMapItemsDelegate icon = (RequestMapItemsDelegate)result.AsyncDelegate; - - OSDMap response = (OSDMap)icon.EndInvoke(iar); - - Interlocked.Decrement(ref nAsyncRequests); - - if (!response.ContainsKey("requestID")) - return; - - UUID requestID = response["requestID"].AsUUID(); - - if (requestID != UUID.Zero) + lock (requests) { - MapRequestState mrs = new MapRequestState(); - mrs.agentID = UUID.Zero; - lock (m_openRequests) - { - if (m_openRequests.ContainsKey(requestID)) - { - mrs = m_openRequests[requestID]; - m_openRequests.Remove(requestID); - } - } - - if (mrs.agentID != UUID.Zero) - { - ScenePresence av = null; - m_scene.TryGetScenePresence(mrs.agentID, out av); - if (av != null) - { - if (response.ContainsKey(mrs.itemtype.ToString())) - { - List returnitems = new List(); - OSDArray itemarray = (OSDArray)response[mrs.itemtype.ToString()]; - for (int i = 0; i < itemarray.Count; i++) - { - OSDMap mapitem = (OSDMap)itemarray[i]; - mapItemReply mi = new mapItemReply(); - mi.x = (uint)mapitem["X"].AsInteger(); - mi.y = (uint)mapitem["Y"].AsInteger(); - mi.id = mapitem["ID"].AsUUID(); - mi.Extra = mapitem["Extra"].AsInteger(); - mi.Extra2 = mapitem["Extra2"].AsInteger(); - mi.name = mapitem["Name"].AsString(); - returnitems.Add(mi); - } - av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags); - } - - // Service 7 (MAP_ITEM_LAND_FOR_SALE) - uint itemtype = 7; - - if (response.ContainsKey(itemtype.ToString())) - { - List returnitems = new List(); - OSDArray itemarray = (OSDArray)response[itemtype.ToString()]; - for (int i = 0; i < itemarray.Count; i++) - { - OSDMap mapitem = (OSDMap)itemarray[i]; - mapItemReply mi = new mapItemReply(); - mi.x = (uint)mapitem["X"].AsInteger(); - mi.y = (uint)mapitem["Y"].AsInteger(); - mi.id = mapitem["ID"].AsUUID(); - mi.Extra = mapitem["Extra"].AsInteger(); - mi.Extra2 = mapitem["Extra2"].AsInteger(); - mi.name = mapitem["Name"].AsString(); - returnitems.Add(mi); - } - av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); - } - - // Service 1 (MAP_ITEM_TELEHUB) - itemtype = 1; - - if (response.ContainsKey(itemtype.ToString())) - { - List returnitems = new List(); - OSDArray itemarray = (OSDArray)response[itemtype.ToString()]; - for (int i = 0; i < itemarray.Count; i++) - { - OSDMap mapitem = (OSDMap)itemarray[i]; - mapItemReply mi = new mapItemReply(); - mi.x = (uint)mapitem["X"].AsInteger(); - mi.y = (uint)mapitem["Y"].AsInteger(); - mi.id = mapitem["ID"].AsUUID(); - mi.Extra = mapitem["Extra"].AsInteger(); - mi.Extra2 = mapitem["Extra2"].AsInteger(); - mi.name = mapitem["Name"].AsString(); - returnitems.Add(mi); - } - av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); - } - } - } + queueEvent.Set(); + requests.Enqueue(state); } } @@ -700,8 +615,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap EnqueueMapItemRequest(st); } - private delegate OSDMap RequestMapItemsDelegate(UUID id, uint flags, - uint EstateID, bool godlike, uint itemtype, ulong regionhandle); /// /// Does the actual remote mapitem request /// This should be called from an asynchronous thread @@ -716,7 +629,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// passed in from packet /// Region we're looking up /// - private OSDMap RequestMapItemsAsync(UUID id, uint flags, + private void RequestMapItemsAsync(UUID id, uint flags, uint EstateID, bool godlike, uint itemtype, ulong regionhandle) { // m_log.DebugFormat("[WORLDMAP]: RequestMapItemsAsync; region handle: {0} {1}", regionhandle, itemtype); @@ -739,7 +652,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } if (blacklisted) - return new OSDMap(); + { + Interlocked.Decrement(ref nAsyncRequests); + return; + } UUID requestID = UUID.Random(); lock (m_cachedRegionMapItemsAddress) @@ -747,6 +663,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle)) httpserver = m_cachedRegionMapItemsAddress[regionhandle]; } + if (httpserver.Length == 0) { uint x = 0, y = 0; @@ -791,18 +708,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap // Can't find the http server if (httpserver.Length == 0 || blacklisted) - return new OSDMap(); - - MapRequestState mrs = new MapRequestState(); - mrs.agentID = id; - mrs.EstateID = EstateID; - mrs.flags = flags; - mrs.godlike = godlike; - mrs.itemtype=itemtype; - mrs.regionhandle = regionhandle; - - lock (m_openRequests) - m_openRequests.Add(requestID, mrs); + { + Interlocked.Decrement(ref nAsyncRequests); + return; + } WebRequest mapitemsrequest = null; try @@ -812,7 +721,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap catch (Exception e) { m_log.DebugFormat("[WORLD MAP]: Access to {0} failed with {1}", httpserver, e); - return new OSDMap(); + Interlocked.Decrement(ref nAsyncRequests); + return; } mapitemsrequest.Method = "POST"; @@ -826,6 +736,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap OSDMap responseMap = new OSDMap(); responseMap["requestID"] = OSD.FromUUID(requestID); +return; Stream os = null; try { // send the Post @@ -837,7 +748,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap catch (WebException ex) { m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message); - responseMap["connect"] = OSD.FromBoolean(false); lock (m_blacklistedurls) { if (!m_blacklistedurls.ContainsKey(httpserver)) @@ -846,13 +756,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver); - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } catch { m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver); - responseMap["connect"] = OSD.FromBoolean(false); - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } finally { @@ -873,12 +784,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } else { - return new OSDMap(); + Interlocked.Decrement(ref nAsyncRequests); + return; } } catch (WebException) { - responseMap["connect"] = OSD.FromBoolean(false); lock (m_blacklistedurls) { if (!m_blacklistedurls.ContainsKey(httpserver)) @@ -887,19 +798,20 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver); - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } catch { m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver); - responseMap["connect"] = OSD.FromBoolean(false); lock (m_blacklistedregions) { if (!m_blacklistedregions.ContainsKey(regionhandle)) m_blacklistedregions.Add(regionhandle, Environment.TickCount); } - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } finally { @@ -918,14 +830,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap catch (Exception ex) { m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message); - responseMap["connect"] = OSD.FromBoolean(false); lock (m_blacklistedregions) { if (!m_blacklistedregions.ContainsKey(regionhandle)) m_blacklistedregions.Add(regionhandle, Environment.TickCount); } - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } } @@ -939,7 +851,78 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } } - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + + if (id != UUID.Zero) + { + ScenePresence av = null; + m_scene.TryGetScenePresence(id, out av); + if (av != null) + { + if (responseMap.ContainsKey(itemtype.ToString())) + { + List returnitems = new List(); + OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()]; + for (int i = 0; i < itemarray.Count; i++) + { + OSDMap mapitem = (OSDMap)itemarray[i]; + mapItemReply mi = new mapItemReply(); + mi.x = (uint)mapitem["X"].AsInteger(); + mi.y = (uint)mapitem["Y"].AsInteger(); + mi.id = mapitem["ID"].AsUUID(); + mi.Extra = mapitem["Extra"].AsInteger(); + mi.Extra2 = mapitem["Extra2"].AsInteger(); + mi.name = mapitem["Name"].AsString(); + returnitems.Add(mi); + } + av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags); + } + + // Service 7 (MAP_ITEM_LAND_FOR_SALE) + itemtype = 7; + + if (responseMap.ContainsKey(itemtype.ToString())) + { + List returnitems = new List(); + OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()]; + for (int i = 0; i < itemarray.Count; i++) + { + OSDMap mapitem = (OSDMap)itemarray[i]; + mapItemReply mi = new mapItemReply(); + mi.x = (uint)mapitem["X"].AsInteger(); + mi.y = (uint)mapitem["Y"].AsInteger(); + mi.id = mapitem["ID"].AsUUID(); + mi.Extra = mapitem["Extra"].AsInteger(); + mi.Extra2 = mapitem["Extra2"].AsInteger(); + mi.name = mapitem["Name"].AsString(); + returnitems.Add(mi); + } + av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags); + } + + // Service 1 (MAP_ITEM_TELEHUB) + itemtype = 1; + + if (responseMap.ContainsKey(itemtype.ToString())) + { + List returnitems = new List(); + OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()]; + for (int i = 0; i < itemarray.Count; i++) + { + OSDMap mapitem = (OSDMap)itemarray[i]; + mapItemReply mi = new mapItemReply(); + mi.x = (uint)mapitem["X"].AsInteger(); + mi.y = (uint)mapitem["Y"].AsInteger(); + mi.id = mapitem["ID"].AsUUID(); + mi.Extra = mapitem["Extra"].AsInteger(); + mi.Extra2 = mapitem["Extra2"].AsInteger(); + mi.name = mapitem["Name"].AsString(); + returnitems.Add(mi); + } + av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags); + } + } + } } /// @@ -951,53 +934,56 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { - //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); - if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible + Util.FireAndForget(x => { - List response = new List(); - - // this should return one mapblock at most. It is triggered by a click - // on an unloaded square. - // But make sure: Look whether the one we requested is in there - List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, - minX * (int)Constants.RegionSize, - maxX * (int)Constants.RegionSize, - minY * (int)Constants.RegionSize, - maxY * (int)Constants.RegionSize); - - if (regions != null) + //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); + if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible { - foreach (GridRegion r in regions) + List response = new List(); + + // this should return one mapblock at most. It is triggered by a click + // on an unloaded square. + // But make sure: Look whether the one we requested is in there + List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, + minX * (int)Constants.RegionSize, + maxX * (int)Constants.RegionSize, + minY * (int)Constants.RegionSize, + maxY * (int)Constants.RegionSize); + + if (regions != null) { - if ((r.RegionLocX == minX * (int)Constants.RegionSize) && - (r.RegionLocY == minY * (int)Constants.RegionSize)) + foreach (GridRegion r in regions) { - // found it => add it to response - MapBlockData block = new MapBlockData(); - MapBlockFromGridRegion(block, r, flag); - response.Add(block); - break; + if ((r.RegionLocX == minX * (int)Constants.RegionSize) && + (r.RegionLocY == minY * (int)Constants.RegionSize)) + { + // found it => add it to response + MapBlockData block = new MapBlockData(); + MapBlockFromGridRegion(block, r, flag); + response.Add(block); + break; + } } } - } - if (response.Count == 0) + if (response.Count == 0) + { + // response still empty => couldn't find the map-tile the user clicked on => tell the client + MapBlockData block = new MapBlockData(); + block.X = (ushort)minX; + block.Y = (ushort)minY; + block.Access = 254; // means 'simulator is offline' + response.Add(block); + } + // The lower 16 bits are an unsigned int16 + remoteClient.SendMapBlock(response, flag & 0xffff); + } + else { - // response still empty => couldn't find the map-tile the user clicked on => tell the client - MapBlockData block = new MapBlockData(); - block.X = (ushort)minX; - block.Y = (ushort)minY; - block.Access = 254; // means 'simulator is offline' - response.Add(block); + // normal mapblock request. Use the provided values + GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); } - // The lower 16 bits are an unsigned int16 - remoteClient.SendMapBlock(response, flag & 0xffff); - } - else - { - // normal mapblock request. Use the provided values - GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); - } + }); } protected virtual List GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) @@ -1013,8 +999,15 @@ namespace OpenSim.Region.CoreModules.World.WorldMap MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r, flag); mapBlocks.Add(block); + if (mapBlocks.Count >= 20) + { + remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); + mapBlocks.Clear(); + Thread.Sleep(1000); + } } - remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); + if (mapBlocks.Count > 0) + remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); return mapBlocks; } -- cgit v1.1 From 73c5a6e66637b9f5f0d7dc3f4bf4c9818223b3e9 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 8 Jul 2012 07:42:40 +0200 Subject: Instead of sending 20 records in 2 packets, send just one as we intended in the first place. --- OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 721ac5c..88aacb9 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -999,7 +999,7 @@ return; MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r, flag); mapBlocks.Add(block); - if (mapBlocks.Count >= 20) + if (mapBlocks.Count >= 10) { remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); mapBlocks.Clear(); -- cgit v1.1 From 1e4c65649736db82d0221b6b2aa57f7f45c7163c Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 8 Jul 2012 10:44:53 +0200 Subject: Revamp map block sending to eliminate overload of the grid server connection and the sim's http client --- .../CoreModules/Hypergrid/HGWorldMapModule.cs | 4 +- .../CoreModules/World/WorldMap/WorldMapModule.cs | 298 ++++++++++++++------- 2 files changed, 204 insertions(+), 98 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index 0c60391..4f18b53 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs @@ -90,9 +90,9 @@ namespace OpenSim.Region.CoreModules.Hypergrid } } - protected override List GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + protected override List GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { - List mapBlocks = base.GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); + List mapBlocks = base.GetAndSendBlocksInternal(remoteClient, minX, minY, maxX, maxY, flag); lock (m_SeenMapBlocks) { if (!m_SeenMapBlocks.ContainsKey(remoteClient.AgentId)) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 88aacb9..a226b78 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -66,6 +66,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private ManualResetEvent queueEvent = new ManualResetEvent(false); private Queue requests = new Queue(); + private ManualResetEvent m_mapBlockRequestEvent = new ManualResetEvent(false); + private Dictionary> m_mapBlockRequests = new Dictionary>(); + protected Scene m_scene; private List cachedMapBlocks = new List(); private int cachedTime = 0; @@ -227,54 +230,54 @@ namespace OpenSim.Region.CoreModules.World.WorldMap // 6/8/2011 -- I'm adding an explicit 2048 check, so that we never forget that there is // a hack here, and so that regions below 4096 don't get spammed with unnecessary map blocks. - if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) - { - ScenePresence avatarPresence = null; - - m_scene.TryGetScenePresence(agentID, out avatarPresence); - - if (avatarPresence != null) - { - bool lookup = false; - - lock (cachedMapBlocks) - { - if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) - { - List mapBlocks; - - mapBlocks = cachedMapBlocks; - avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); - } - else - { - lookup = true; - } - } - if (lookup) - { - List mapBlocks = new List(); ; - - List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, - (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, - (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, - (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, - (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); - foreach (GridRegion r in regions) - { - MapBlockData block = new MapBlockData(); - MapBlockFromGridRegion(block, r, 0); - mapBlocks.Add(block); - } - avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); - - lock (cachedMapBlocks) - cachedMapBlocks = mapBlocks; - - cachedTime = Util.UnixTimeSinceEpoch(); - } - } - } + //if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) + //{ + // ScenePresence avatarPresence = null; + + // m_scene.TryGetScenePresence(agentID, out avatarPresence); + + // if (avatarPresence != null) + // { + // bool lookup = false; + + // lock (cachedMapBlocks) + // { + // if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) + // { + // List mapBlocks; + + // mapBlocks = cachedMapBlocks; + // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); + // } + // else + // { + // lookup = true; + // } + // } + // if (lookup) + // { + // List mapBlocks = new List(); ; + + // List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, + // (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, + // (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, + // (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, + // (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); + // foreach (GridRegion r in regions) + // { + // MapBlockData block = new MapBlockData(); + // MapBlockFromGridRegion(block, r, 0); + // mapBlocks.Add(block); + // } + // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); + + // lock (cachedMapBlocks) + // cachedMapBlocks = mapBlocks; + + // cachedTime = Util.UnixTimeSinceEpoch(); + // } + // } + //} LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); @@ -301,8 +304,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap protected static OSDMapLayer GetOSDMapLayerResponse() { OSDMapLayer mapLayer = new OSDMapLayer(); - mapLayer.Right = 5000; - mapLayer.Top = 5000; + mapLayer.Right = 2048; + mapLayer.Top = 2048; mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); return mapLayer; @@ -331,6 +334,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap { m_rootAgents.Remove(AgentId); } + lock (m_mapBlockRequestEvent) + { + if (m_mapBlockRequests.ContainsKey(AgentId)) + m_mapBlockRequests.Remove(AgentId); + } } #endregion @@ -353,6 +361,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap ThreadPriority.BelowNormal, true, true); + Watchdog.StartThread( + MapBlockSendThread, + string.Format("MapBlockSendThread ({0})", m_scene.RegionInfo.RegionName), + ThreadPriority.BelowNormal, + true, + true); } /// @@ -373,6 +387,22 @@ namespace OpenSim.Region.CoreModules.World.WorldMap queueEvent.Set(); requests.Enqueue(st); } + + MapBlockRequestData req = new MapBlockRequestData(); + + req.client = null; + req.minX = 0; + req.maxX = 0; + req.minY = 0; + req.maxY = 0; + req.flags = 0; + + lock (m_mapBlockRequestEvent) + { + m_mapBlockRequests[UUID.Zero] = new Queue(); + m_mapBlockRequests[UUID.Zero].Enqueue(req); + m_mapBlockRequestEvent.Set(); + } } public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, @@ -932,84 +962,144 @@ return; /// /// /// - public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + public void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { - Util.FireAndForget(x => + //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); + if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible { - //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); - if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible + List response = new List(); + + // this should return one mapblock at most. It is triggered by a click + // on an unloaded square. + // But make sure: Look whether the one we requested is in there + List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, + minX * (int)Constants.RegionSize, + maxX * (int)Constants.RegionSize, + minY * (int)Constants.RegionSize, + maxY * (int)Constants.RegionSize); + + if (regions != null) { - List response = new List(); - - // this should return one mapblock at most. It is triggered by a click - // on an unloaded square. - // But make sure: Look whether the one we requested is in there - List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, - minX * (int)Constants.RegionSize, - maxX * (int)Constants.RegionSize, - minY * (int)Constants.RegionSize, - maxY * (int)Constants.RegionSize); - - if (regions != null) + foreach (GridRegion r in regions) { - foreach (GridRegion r in regions) + if ((r.RegionLocX == minX * (int)Constants.RegionSize) && + (r.RegionLocY == minY * (int)Constants.RegionSize)) { - if ((r.RegionLocX == minX * (int)Constants.RegionSize) && - (r.RegionLocY == minY * (int)Constants.RegionSize)) - { - // found it => add it to response - MapBlockData block = new MapBlockData(); - MapBlockFromGridRegion(block, r, flag); - response.Add(block); - break; - } + // found it => add it to response + MapBlockData block = new MapBlockData(); + MapBlockFromGridRegion(block, r, flag); + response.Add(block); + break; } } + } - if (response.Count == 0) + if (response.Count == 0) + { + // response still empty => couldn't find the map-tile the user clicked on => tell the client + MapBlockData block = new MapBlockData(); + block.X = (ushort)minX; + block.Y = (ushort)minY; + block.Access = 254; // means 'simulator is offline' + response.Add(block); + } + // The lower 16 bits are an unsigned int16 + remoteClient.SendMapBlock(response, flag & 0xffff); + } + else + { + // normal mapblock request. Use the provided values + GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); + } + } + + protected virtual List GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + { + MapBlockRequestData req = new MapBlockRequestData(); + + req.client = remoteClient; + req.minX = minX; + req.maxX = maxX; + req.minY = minY; + req.maxY = maxY; + req.flags = flag; + + lock (m_mapBlockRequestEvent) + { + if (!m_mapBlockRequests.ContainsKey(remoteClient.AgentId)) + m_mapBlockRequests[remoteClient.AgentId] = new Queue(); + m_mapBlockRequests[remoteClient.AgentId].Enqueue(req); + m_mapBlockRequestEvent.Set(); + } + + return new List(); + } + + protected void MapBlockSendThread() + { + while (true) + { + List thisRunData = new List(); + + m_mapBlockRequestEvent.WaitOne(); + lock (m_mapBlockRequestEvent) + { + int total = 0; + foreach (Queue q in m_mapBlockRequests.Values) { - // response still empty => couldn't find the map-tile the user clicked on => tell the client - MapBlockData block = new MapBlockData(); - block.X = (ushort)minX; - block.Y = (ushort)minY; - block.Access = 254; // means 'simulator is offline' - response.Add(block); + if (q.Count > 0) + thisRunData.Add(q.Dequeue()); + + total += q.Count; } - // The lower 16 bits are an unsigned int16 - remoteClient.SendMapBlock(response, flag & 0xffff); + + if (total == 0) + m_mapBlockRequestEvent.Reset(); } - else + + foreach (MapBlockRequestData req in thisRunData) { - // normal mapblock request. Use the provided values - GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); + // Null client stops thread + if (req.client == null) + return; + + GetAndSendBlocksInternal(req.client, req.minX, req.minY, req.maxX, req.maxY, req.flags); } - }); + + Thread.Sleep(50); + } } - protected virtual List GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + protected virtual List GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { + List allBlocks = new List(); List mapBlocks = new List(); List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, - (minX - 4) * (int)Constants.RegionSize, - (maxX + 4) * (int)Constants.RegionSize, - (minY - 4) * (int)Constants.RegionSize, - (maxY + 4) * (int)Constants.RegionSize); + minX * (int)Constants.RegionSize, + maxX * (int)Constants.RegionSize, + minY * (int)Constants.RegionSize, + maxY * (int)Constants.RegionSize); +// (minX - 4) * (int)Constants.RegionSize, +// (maxX + 4) * (int)Constants.RegionSize, +// (minY - 4) * (int)Constants.RegionSize, +// (maxY + 4) * (int)Constants.RegionSize); foreach (GridRegion r in regions) { MapBlockData block = new MapBlockData(); MapBlockFromGridRegion(block, r, flag); mapBlocks.Add(block); + allBlocks.Add(block); if (mapBlocks.Count >= 10) { remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); mapBlocks.Clear(); - Thread.Sleep(1000); + Thread.Sleep(50); } } if (mapBlocks.Count > 0) remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); - return mapBlocks; + return allBlocks; } protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag) @@ -1408,6 +1498,12 @@ return; { m_rootAgents.Remove(avatar.UUID); } + + lock (m_mapBlockRequestEvent) + { + if (m_mapBlockRequests.ContainsKey(avatar.UUID)) + m_mapBlockRequests.Remove(avatar.UUID); + } } public void OnRegionUp(GridRegion otherRegion) @@ -1531,4 +1627,14 @@ return; public uint itemtype; public ulong regionhandle; } + + public struct MapBlockRequestData + { + public IClientAPI client; + public int minX; + public int minY; + public int maxX; + public int maxY; + public uint flags; + } } -- cgit v1.1 From 1077d7b6f5874a036752f1ca672ce6b8c41004a0 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 8 Jul 2012 21:53:23 +0200 Subject: Reinstate parallel fetching of residents and remove a left over return from debugging --- OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index a226b78..1dedcce 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -553,7 +553,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// public void process() { - const int MAX_ASYNC_REQUESTS = 5; + const int MAX_ASYNC_REQUESTS = 20; try { while (true) @@ -589,11 +589,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle)) { -// while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break -// Thread.Sleep(500); + while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break + Thread.Sleep(100); Interlocked.Increment(ref nAsyncRequests); - RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); + Util.FireAndForget(x => + { + RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); + }); } } @@ -766,7 +769,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap OSDMap responseMap = new OSDMap(); responseMap["requestID"] = OSD.FromUUID(requestID); -return; Stream os = null; try { // send the Post -- cgit v1.1 From fb8e8dcbce6b2ecbb8fbfe8278657260ac55e823 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 9 Jul 2012 13:25:17 +0100 Subject: fix ODE dispose plus minor clean. On regions restart ode.dispose seems to be called with scene still calling simulation, that should be changed, for now added a check for a valid world in ode simulation --- OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs | 58 ++++++++++++++++++------ 1 file changed, 43 insertions(+), 15 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs index 4552f3f..5920838 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs @@ -268,7 +268,7 @@ namespace OpenSim.Region.Physics.OdePlugin public ContactData[] m_materialContactsData = new ContactData[8]; - private readonly DoubleDictionary RegionTerrain = new DoubleDictionary(); + private readonly Dictionary RegionTerrain = new Dictionary(); private readonly Dictionary TerrainHeightFieldHeights = new Dictionary(); private readonly Dictionary TerrainHeightFieldHeightsHandlers = new Dictionary(); @@ -1892,18 +1892,22 @@ namespace OpenSim.Region.Physics.OdePlugin lock (SimulationLock) lock(OdeLock) { + if (world == IntPtr.Zero) + return 0; + // adjust number of iterations per step - try - { + +// try +// { d.WorldSetQuickStepNumIterations(world, curphysiteractions); - } +/* } catch (StackOverflowException) { m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim."); // ode.drelease(world); base.TriggerPhysicsBasedRestart(); } - +*/ while (step_time > HalfOdeStep && nodeframes < 10) //limit number of steps so we don't say here for ever { try @@ -2383,11 +2387,9 @@ namespace OpenSim.Region.Physics.OdePlugin d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); d.GeomSetRotation(GroundGeom, ref R); d.GeomSetPosition(GroundGeom, pOffset.X + (float)Constants.RegionSize * 0.5f, pOffset.Y + (float)Constants.RegionSize * 0.5f, 0); - RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); -// TerrainHeightFieldHeights.Add(GroundGeom, ODElandMap); + RegionTerrain.Add(pOffset, GroundGeom); TerrainHeightFieldHeights.Add(GroundGeom, _heightmap); - TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler); - + TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler); } } @@ -2486,8 +2488,7 @@ namespace OpenSim.Region.Physics.OdePlugin geom_name_map[GroundGeom] = "Terrain"; d.GeomSetPosition(GroundGeom, pOffset.X + (float)Constants.RegionSize * 0.5f, pOffset.Y + (float)Constants.RegionSize * 0.5f, 0); - RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); - // TerrainHeightFieldHeights.Add(GroundGeom, ODElandMap); + RegionTerrain.Add(pOffset, GroundGeom); TerrainHeightFieldHeights.Add(GroundGeom, _heightmap); TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler); } @@ -2649,19 +2650,42 @@ namespace OpenSim.Region.Physics.OdePlugin public override void Dispose() { - m_rayCastManager.Dispose(); - m_rayCastManager = null; - lock (OdeLock) { + m_rayCastManager.Dispose(); + m_rayCastManager = null; + lock (_prims) { + ChangesQueue.Clear(); foreach (OdePrim prm in _prims) { - RemovePrim(prm); + prm.DoAChange(changes.Remove, null); + _collisionEventPrim.Remove(prm); } + _prims.Clear(); } + OdeCharacter[] chtorem; + lock (_characters) + { + chtorem = new OdeCharacter[_characters.Count]; + _characters.CopyTo(chtorem); + } + + ChangesQueue.Clear(); + foreach (OdeCharacter ch in chtorem) + ch.DoAChange(changes.Remove, null); + + + foreach (IntPtr GroundGeom in RegionTerrain.Values) + { + if (GroundGeom != IntPtr.Zero) + d.GeomDestroy(GroundGeom); + } + + RegionTerrain.Clear(); + if (TerrainHeightFieldHeightsHandlers.Count > 0) { foreach (GCHandle gch in TerrainHeightFieldHeightsHandlers.Values) @@ -2671,6 +2695,9 @@ namespace OpenSim.Region.Physics.OdePlugin } } + TerrainHeightFieldHeightsHandlers.Clear(); + TerrainHeightFieldHeights.Clear(); + if (WaterGeom != IntPtr.Zero) { d.GeomDestroy(WaterGeom); @@ -2691,6 +2718,7 @@ namespace OpenSim.Region.Physics.OdePlugin d.WorldDestroy(world); + world = IntPtr.Zero; //d.CloseODE(); } } -- cgit v1.1 From 0ac161c9a89075b414941d00b34b50e16c023a51 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 9 Jul 2012 16:51:56 +0100 Subject: log ODE lib configuration --- OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs index 5920838..46251de 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs @@ -175,7 +175,7 @@ namespace OpenSim.Region.Physics.OdePlugin const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce; const float MaxERP = 0.8f; - const float minERP = 0.1f; + const float minERP = 0.2f; const float comumContactCFM = 0.0001f; float frictionMovementMult = 0.8f; @@ -408,7 +408,7 @@ namespace OpenSim.Region.Physics.OdePlugin // checkThread(); mesher = meshmerizer; m_config = config; -/* + string ode_config = d.GetConfiguration("ODE"); if (ode_config != null && ode_config != "") { @@ -419,7 +419,7 @@ namespace OpenSim.Region.Physics.OdePlugin OdeUbitLib = true; } } -*/ + /* if (region != null) { @@ -921,6 +921,8 @@ namespace OpenSim.Region.Physics.OdePlugin cfm = 0.0001f / cfm; if (cfm > 0.01f) cfm = 0.01f; + else if (cfm < 0.0001f) + cfm = 0.0001f; if ((Math.Abs(p2.Velocity.X - p1.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y - p1.Velocity.Y) > 0.1f)) mu *= frictionMovementMult; @@ -947,6 +949,8 @@ namespace OpenSim.Region.Physics.OdePlugin cfm = 0.0001f / cfm; if (cfm > 0.01f) cfm = 0.01f; + else if (cfm < 0.0001f) + cfm = 0.0001f; if (d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass) { -- cgit v1.1 From a7097680851528f01477903d946095abce99e504 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 9 Jul 2012 17:01:52 +0100 Subject: fix ode getconfiguration --- OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs | 2 +- OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs index 0e4961b..34865c1 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs @@ -1312,7 +1312,7 @@ namespace OdeAPI public static extern void GeomTriMeshSetRayCallback(IntPtr g, TriRayCallback callback); [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGetConfiguration"), SuppressUnmanagedCodeSecurity] - public static extern string GetConfiguration(string str); + public static extern string GetConfiguration(); [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dHashSpaceCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr HashSpaceCreate(IntPtr space); diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs index 46251de..d5938f4 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs @@ -409,7 +409,7 @@ namespace OpenSim.Region.Physics.OdePlugin mesher = meshmerizer; m_config = config; - string ode_config = d.GetConfiguration("ODE"); + string ode_config = d.GetConfiguration(); if (ode_config != null && ode_config != "") { m_log.WarnFormat("ODE configuration: {0}", ode_config); -- cgit v1.1 From 3a1d46ad446cb4d5d0f193bd9d7cdcfc4f65a565 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 9 Jul 2012 17:21:54 +0100 Subject: retry fixing ode getconfiguration() --- OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs index 34865c1..2341186 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs @@ -1312,7 +1312,14 @@ namespace OdeAPI public static extern void GeomTriMeshSetRayCallback(IntPtr g, TriRayCallback callback); [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGetConfiguration"), SuppressUnmanagedCodeSecurity] - public static extern string GetConfiguration(); + public static extern IntPtr iGetConfiguration(); + + public static string GetConfiguration() + { + IntPtr ptr = iGetConfiguration(); + string s = Marshal.PtrToStringAnsi(ptr); + return s; + } [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dHashSpaceCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr HashSpaceCreate(IntPtr space); -- cgit v1.1 From ca41ec9eb4616c0cb96ed48d591e473d95af2701 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 10 Jul 2012 05:11:06 +0100 Subject: let rotationVelocity or AngularVelocity be setted on prims. Limited to 12rad/s --- OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs | 65 +++++++++++++++++-------- 1 file changed, 46 insertions(+), 19 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs index 3d8e680..14e4272 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs @@ -583,8 +583,6 @@ namespace OpenSim.Region.Physics.OdePlugin if (value.IsFinite()) { AddChange(changes.Velocity, value); -// _velocity = value; - } else { @@ -676,9 +674,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if (value.IsFinite()) { - m_rotationalVelocity = value; - if (Body != IntPtr.Zero && !d.BodyIsEnabled(Body)) - d.BodyEnable(Body); + AddChange(changes.AngVelocity, value); } else { @@ -687,7 +683,6 @@ namespace OpenSim.Region.Physics.OdePlugin } } - public override float Buoyancy { get { return m_buoyancy; } @@ -1737,17 +1732,14 @@ namespace OpenSim.Region.Physics.OdePlugin d.BodySetAutoDisableFlag(Body, true); d.BodySetAutoDisableSteps(Body, body_autodisable_frames); -// d.BodySetLinearDampingThreshold(Body, 0.01f); -// d.BodySetAngularDampingThreshold(Body, 0.001f); - d.BodySetDamping(Body, .002f, .002f); - - if (m_targetSpace != IntPtr.Zero) - { - _parent_scene.waitForSpaceUnlock(m_targetSpace); - if (d.SpaceQuery(m_targetSpace, prim_geom)) - d.SpaceRemove(m_targetSpace, prim_geom); - } + d.BodySetDamping(Body, .005f, .005f); + if (m_targetSpace != IntPtr.Zero) + { + _parent_scene.waitForSpaceUnlock(m_targetSpace); + if (d.SpaceQuery(m_targetSpace, prim_geom)) + d.SpaceRemove(m_targetSpace, prim_geom); + } if (childrenPrim.Count == 0) { @@ -3296,6 +3288,13 @@ namespace OpenSim.Region.Physics.OdePlugin private void changevelocity(Vector3 newVel) { + float len = newVel.LengthSquared(); + if (len > 100000.0f) // limit to 100m/s + { + len = 100.0f / (float)Math.Sqrt(len); + newVel *= len; + } + if (!m_isSelected) { if (Body != IntPtr.Zero) @@ -3312,6 +3311,33 @@ namespace OpenSim.Region.Physics.OdePlugin _velocity = newVel; } + + private void changeangvelocity(Vector3 newAngVel) + { + float len = newAngVel.LengthSquared(); + if (len > 144.0f) // limit to 12rad/s + { + len = 12.0f / (float)Math.Sqrt(len); + newAngVel *= len; + } + + if (!m_isSelected) + { + if (Body != IntPtr.Zero) + { + if (m_disabled) + enableBodySoft(); + else if (!d.BodyIsEnabled(Body)) + d.BodyEnable(Body); + + + d.BodySetAngularVel(Body, newAngVel.X, newAngVel.Y, newAngVel.Z); + } + //resetCollisionAccounting(); + } + m_rotationalVelocity = newAngVel; + } + private void changeVolumedetetion(bool newVolDtc) { m_isVolumeDetect = newVolDtc; @@ -3948,9 +3974,10 @@ namespace OpenSim.Region.Physics.OdePlugin // case changes.Acceleration: // changeacceleration((Vector3)arg); // break; -// case changes.AngVelocity: -// changeangvelocity((Vector3)arg); -// break; + + case changes.AngVelocity: + changeangvelocity((Vector3)arg); + break; case changes.Force: changeForce((Vector3)arg); -- cgit v1.1 From 652ac5f66bacb048628bc953497ffe4256676f05 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 10 Jul 2012 05:28:47 +0100 Subject: more work on llSetAngularVelocity() --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 29 +++++++++++++++++++++- .../Shared/Api/Implementation/LSL_Api.cs | 4 +-- 2 files changed, 29 insertions(+), 4 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index dd30a59..0f44823 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1845,7 +1845,7 @@ namespace OpenSim.Region.Framework.Scenes } } -// SetVelocity for LSL llSetVelocity.. may need revision if having other uses in future + // SetVelocity for LSL llSetVelocity.. may need revision if having other uses in future public void SetVelocity(Vector3 pVel, bool localGlobalTF) { if (ParentGroup == null || ParentGroup.IsDeleted) @@ -1871,6 +1871,33 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.Velocity = pVel; } + + // SetAngularVelocity for LSL llSetAngularVelocity.. may need revision if having other uses in future + public void SetAngularVelocity(Vector3 pAngVel, bool localGlobalTF) + { + if (ParentGroup == null || ParentGroup.IsDeleted) + return; + + if (ParentGroup.IsAttachment) + return; // don't work on attachments (for now ??) + + SceneObjectPart root = ParentGroup.RootPart; + + if (root.VehicleType != (int)Vehicle.TYPE_NONE) // don't mess with vehicles + return; + + PhysicsActor pa = root.PhysActor; + + if (pa == null || !pa.IsPhysical) + return; + + if (localGlobalTF) + { + pAngVel = pAngVel * GetWorldRotation(); + } + + root.AngularVelocity = pAngVel; + } /// diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 0ee2748..cae7343 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2597,12 +2597,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z); } - public void llSetAngularVelocity(LSL_Vector avel, int local) { m_host.AddScriptLPS(1); - // Still not done !!!! -// m_host.SetAngularVelocity(new Vector3((float)avel.x, (float)avel.y, (float)avel.z), local != 0); + m_host.SetAngularVelocity(new Vector3((float)avel.x, (float)avel.y, (float)avel.z), local != 0); } public LSL_Vector llGetOmega() -- cgit v1.1 From acec9da95c2faa861ee37cc5e820118fc4649c80 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 10 Jul 2012 05:37:41 +0100 Subject: let SOP AngularVelocity set physics actor angular velocity if it's physical root prim and not a vehicle. With this llSetAngularVelocity should work and also llTargetOmega will do the same in this case. but for now this llTargetOmega is being a normal physical rotation with damping, and stops with selection. Thats not like SL apparently --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 0f44823..16a8588 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -959,7 +959,15 @@ namespace OpenSim.Region.Framework.Scenes } return m_angularVelocity; } - set { m_angularVelocity = value; } + set + { + m_angularVelocity = value; + PhysicsActor actor = PhysActor; + if ((actor != null) && actor.IsPhysical && ParentGroup.RootPart == this && VehicleType == (int)Vehicle.TYPE_NONE) + { + actor.RotationalVelocity = m_angularVelocity; + } + } } /// -- cgit v1.1 From df55de5b3d88e241f35217d5c08d02b921991513 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 10 Jul 2012 05:51:41 +0100 Subject: lltargetomega efective spinrate now multiplied by gain ( need check ) --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index cae7343..05bb161 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -3804,6 +3804,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected void TargetOmega(SceneObjectPart part, LSL_Vector axis, double spinrate, double gain) { + spinrate *= gain; part.UpdateAngularVelocity(new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate))); } -- cgit v1.1 From 6b8b7007c4a8c5ed3386093fd0cfac0032587121 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Tue, 10 Jul 2012 18:23:38 +0100 Subject: console region restart: Let Xengine not cry all over the place with errors also. May not be that good, but is not in use in AVN (i hope). Still safer to do a full shutdown and refire the region from a OS tool like a script, monit, etc etc --- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 1e0f01f..2a01fc4 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -596,7 +596,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (!m_Enabled) return; lockScriptsForRead(true); - foreach (IScriptInstance instance in m_Scripts.Values) + + List instancesToDel = new List(m_Scripts.Values); + +// foreach (IScriptInstance instance in m_Scripts.Values) + foreach (IScriptInstance instance in instancesToDel) { // Force a final state save // @@ -619,7 +623,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine // Must be done explicitly because they have infinite // lifetime // - if (!m_SimulatorShuttingDown) +// if (!m_SimulatorShuttingDown) { m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); if (m_DomainScripts[instance.AppDomain].Count == 0) @@ -629,10 +633,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine } } - m_Scripts.Clear(); - m_PrimObjects.Clear(); - m_Assemblies.Clear(); - m_DomainScripts.Clear(); +// m_Scripts.Clear(); +// m_PrimObjects.Clear(); +// m_Assemblies.Clear(); +// m_DomainScripts.Clear(); } lockScriptsForRead(false); lockScriptsForWrite(true); -- cgit v1.1 From 7836933133a27bb57cd89663134f37b78fed5f7c Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 11 Jul 2012 03:58:58 +0100 Subject: Melanie fix: detach SOGs from backup on linking --- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index a600b86..0587846 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -1820,6 +1820,8 @@ namespace OpenSim.Region.Framework.Scenes { parentGroup.LinkToGroup(child); + child.DetachFromBackup(); + // this is here so physics gets updated! // Don't remove! Bad juju! Stay away! or fix physics! child.AbsolutePosition = child.AbsolutePosition; -- cgit v1.1 From 84ab4c44628441b32ec7ef0c728d035b5cf40b39 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 11 Jul 2012 08:13:57 +0100 Subject: ubitODE leaks --- .../Region/Physics/UbitOdePlugin/ODECharacter.cs | 2 + OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs | 2 + OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs | 54 ++++++++++++---------- 3 files changed, 33 insertions(+), 25 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs index 6e4e41f..865180f 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs @@ -740,6 +740,7 @@ namespace OpenSim.Region.Physics.OdePlugin if (Shell != IntPtr.Zero) { _parent_scene.geom_name_map.Remove(Shell); + _parent_scene.actor_name_map.Remove(Shell); _parent_scene.waitForSpaceUnlock(_parent_scene.ActiveSpace); d.GeomDestroy(Shell); Shell = IntPtr.Zero; @@ -1188,6 +1189,7 @@ namespace OpenSim.Region.Physics.OdePlugin } else { + _parent_scene.RemoveCollisionEventReporting(this); _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data AvatarGeomAndBodyDestroy(); diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs index 14e4272..ff17a6e 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs @@ -943,6 +943,8 @@ namespace OpenSim.Region.Physics.OdePlugin CollisionEventsThisFrame = null; } m_eventsubscription = 0; + // for now still done on odescene +// _parent_scene.RemoveCollisionEventReporting(this); } public void AddCollisionEvent(uint CollidedWith, ContactPoint contact) diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs index d5938f4..7848b35 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs @@ -175,7 +175,7 @@ namespace OpenSim.Region.Physics.OdePlugin const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce; const float MaxERP = 0.8f; - const float minERP = 0.2f; + const float minERP = 0.1f; const float comumContactCFM = 0.0001f; float frictionMovementMult = 0.8f; @@ -237,20 +237,20 @@ namespace OpenSim.Region.Physics.OdePlugin private d.NearCallback nearCallback; - private readonly HashSet _characters = new HashSet(); - private readonly HashSet _prims = new HashSet(); - private readonly HashSet _activeprims = new HashSet(); - private readonly HashSet _activegroups = new HashSet(); + private HashSet _characters = new HashSet(); + private HashSet _prims = new HashSet(); + private HashSet _activeprims = new HashSet(); + private HashSet _activegroups = new HashSet(); public OpenSim.Framework.LocklessQueue ChangesQueue = new OpenSim.Framework.LocklessQueue(); /// /// A list of actors that should receive collision events. /// - private readonly List _collisionEventPrim = new List(); - private readonly List _collisionEventPrimRemove = new List(); + private List _collisionEventPrim = new List(); + private List _collisionEventPrimRemove = new List(); - private readonly HashSet _badCharacter = new HashSet(); + private HashSet _badCharacter = new HashSet(); public Dictionary geom_name_map = new Dictionary(); public Dictionary actor_name_map = new Dictionary(); @@ -264,26 +264,21 @@ namespace OpenSim.Region.Physics.OdePlugin private volatile int m_global_contactcount = 0; - private readonly IntPtr contactgroup; + private IntPtr contactgroup; public ContactData[] m_materialContactsData = new ContactData[8]; - private readonly Dictionary RegionTerrain = new Dictionary(); - private readonly Dictionary TerrainHeightFieldHeights = new Dictionary(); - private readonly Dictionary TerrainHeightFieldHeightsHandlers = new Dictionary(); + private Dictionary RegionTerrain = new Dictionary(); + private Dictionary TerrainHeightFieldHeights = new Dictionary(); + private Dictionary TerrainHeightFieldHeightsHandlers = new Dictionary(); private int m_physicsiterations = 10; private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag - private readonly PhysicsActor PANull = new NullPhysicsActor(); + private PhysicsActor PANull = new NullPhysicsActor(); private float step_time = 0.0f; public IntPtr world; - private uint obj2LocalID = 0; - private OdeCharacter cc1; - private OdePrim cp1; - private OdeCharacter cc2; - private OdePrim cp2; // split the spaces acording to contents type // ActiveSpace contains characters and active prims @@ -921,8 +916,8 @@ namespace OpenSim.Region.Physics.OdePlugin cfm = 0.0001f / cfm; if (cfm > 0.01f) cfm = 0.01f; - else if (cfm < 0.0001f) - cfm = 0.0001f; + else if (cfm < 0.00001f) + cfm = 0.00001f; if ((Math.Abs(p2.Velocity.X - p1.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y - p1.Velocity.Y) > 0.1f)) mu *= frictionMovementMult; @@ -949,8 +944,8 @@ namespace OpenSim.Region.Physics.OdePlugin cfm = 0.0001f / cfm; if (cfm > 0.01f) cfm = 0.01f; - else if (cfm < 0.0001f) - cfm = 0.0001f; + else if (cfm < 0.00001f) + cfm = 0.00001f; if (d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass) { @@ -993,6 +988,8 @@ namespace OpenSim.Region.Physics.OdePlugin cfm = 0.0001f / cfm; if (cfm > 0.01f) cfm = 0.01f; + else if (cfm < 0.00001f) + cfm = 0.00001f; if (curContact.side1 > 0) // should be 2 ? IgnoreNegSides = true; @@ -1159,7 +1156,13 @@ namespace OpenSim.Region.Physics.OdePlugin private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) { - obj2LocalID = 0; + + OdeCharacter cc1; + OdePrim cp1; + OdeCharacter cc2; + OdePrim cp2; + + uint obj2LocalID = 0; bool p1events = p1.SubscribedEvents(); bool p2events = p2.SubscribedEvents(); @@ -1963,6 +1966,7 @@ namespace OpenSim.Region.Physics.OdePlugin { RemoveCharacter(defect); } + defects.Clear(); } } @@ -2068,13 +2072,13 @@ namespace OpenSim.Region.Physics.OdePlugin _badCharacter.Clear(); } } - +/* int nactivegeoms = d.SpaceGetNumGeoms(ActiveSpace); int nstaticgeoms = d.SpaceGetNumGeoms(StaticSpace); int ntopgeoms = d.SpaceGetNumGeoms(TopSpace); int nbodies = d.NTotalBodies; int ngeoms = d.NTotalGeoms; - +*/ // Finished with all sim stepping. If requested, dump world state to file for debugging. // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? -- cgit v1.1 From 6252114ea02c07bab2b61fa882f4a26264cbb347 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 11 Jul 2012 09:03:18 +0100 Subject: remove expensive and leaked ( in Xengine at least) SayShout timer and replace it by a simpler function that should do the same (?) (don't like much those 10 + 1 bursts) --- .../Shared/Api/Implementation/LSL_Api.cs | 28 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 05bb161..ca62bac 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -108,8 +108,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected Dictionary m_userInfoCache = new Dictionary(); - protected Timer m_ShoutSayTimer; +// protected Timer m_ShoutSayTimer; protected int m_SayShoutCount = 0; + DateTime m_lastSayShoutCheck; private Dictionary MovementAnimationsForLSL = new Dictionary { @@ -135,10 +136,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) { +/* m_ShoutSayTimer = new Timer(1000); m_ShoutSayTimer.Elapsed += SayShoutTimerElapsed; m_ShoutSayTimer.AutoReset = true; m_ShoutSayTimer.Start(); +*/ + m_lastSayShoutCheck = DateTime.UtcNow; m_ScriptEngine = ScriptEngine; m_host = host; @@ -900,12 +904,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api wComm.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, text); } + private void CheckSayShoutTime() + { + DateTime now = DateTime.UtcNow; + if ((now - m_lastSayShoutCheck).Ticks > 10000000) // 1sec + { + m_lastSayShoutCheck = now; + m_SayShoutCount = 0; + } + else + m_SayShoutCount++; + } + public void llSay(int channelID, string text) { m_host.AddScriptLPS(1); if (channelID == 0) - m_SayShoutCount++; +// m_SayShoutCount++; + CheckSayShoutTime(); if (m_SayShoutCount >= 11) ScriptSleep(2000); @@ -933,7 +950,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); if (channelID == 0) - m_SayShoutCount++; +// m_SayShoutCount++; + CheckSayShoutTime(); if (m_SayShoutCount >= 11) ScriptSleep(2000); @@ -12373,12 +12391,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return rq.ToString(); } - +/* private void SayShoutTimerElapsed(Object sender, ElapsedEventArgs args) { m_SayShoutCount = 0; } - +*/ private struct Tri { public Vector3 p1; -- cgit v1.1