diff options
author | onefang | 2019-09-11 16:36:50 +1000 |
---|---|---|
committer | onefang | 2019-09-11 16:36:50 +1000 |
commit | 50cd1ffd32f69228e566f2b0b89f86ea0d9fe489 (patch) | |
tree | 52f2ab0c04f1a5d7d6ac5dc872981b4b156447e7 /OpenSim/Region/ClientStack | |
parent | Renamed branch to SledjChisl. (diff) | |
parent | Bump to release flavour, build 0. (diff) | |
download | opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.zip opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.gz opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.bz2 opensim-SC_OLD-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.xz |
Merge branch 'SledjChisl'
Diffstat (limited to 'OpenSim/Region/ClientStack')
37 files changed, 6203 insertions, 3851 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs index aabdb51..8f65a69 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs | |||
@@ -133,7 +133,7 @@ namespace OpenSim.Region.ClientStack.LindenCaps | |||
133 | { | 133 | { |
134 | data = new AgentPrefs(agent); | 134 | data = new AgentPrefs(agent); |
135 | } | 135 | } |
136 | 136 | ||
137 | if (req.ContainsKey("access_prefs")) | 137 | if (req.ContainsKey("access_prefs")) |
138 | { | 138 | { |
139 | OSDMap accessPrefs = (OSDMap)req["access_prefs"]; // We could check with ContainsKey... | 139 | OSDMap accessPrefs = (OSDMap)req["access_prefs"]; // We could check with ContainsKey... |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs index bbadc55..e3c430c 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs | |||
@@ -53,7 +53,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
53 | public class AvatarPickerSearchModule : INonSharedRegionModule | 53 | public class AvatarPickerSearchModule : INonSharedRegionModule |
54 | { | 54 | { |
55 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 55 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
56 | 56 | ||
57 | private Scene m_scene; | 57 | private Scene m_scene; |
58 | private IPeople m_People; | 58 | private IPeople m_People; |
59 | private bool m_Enabled = false; | 59 | private bool m_Enabled = false; |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 774202e..50b83f6 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs | |||
@@ -26,11 +26,14 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Timers; | ||
29 | using System.Collections; | 30 | using System.Collections; |
30 | using System.Collections.Generic; | 31 | using System.Collections.Generic; |
32 | using System.Collections.Specialized; | ||
31 | using System.IO; | 33 | using System.IO; |
32 | using System.Reflection; | 34 | using System.Reflection; |
33 | using System.Text; | 35 | using System.Text; |
36 | using System.Web; | ||
34 | 37 | ||
35 | using OpenMetaverse; | 38 | using OpenMetaverse; |
36 | using OpenMetaverse.StructuredData; | 39 | using OpenMetaverse.StructuredData; |
@@ -40,11 +43,11 @@ using log4net; | |||
40 | using OpenSim.Framework; | 43 | using OpenSim.Framework; |
41 | using OpenSim.Framework.Capabilities; | 44 | using OpenSim.Framework.Capabilities; |
42 | using OpenSim.Region.Framework; | 45 | using OpenSim.Region.Framework; |
46 | using OpenSim.Region.Framework.Interfaces; | ||
43 | using OpenSim.Region.Framework.Scenes; | 47 | using OpenSim.Region.Framework.Scenes; |
44 | using OpenSim.Region.Framework.Scenes.Serialization; | 48 | using OpenSim.Region.Framework.Scenes.Serialization; |
45 | using OpenSim.Framework.Servers; | 49 | using OpenSim.Framework.Servers; |
46 | using OpenSim.Framework.Servers.HttpServer; | 50 | using OpenSim.Framework.Servers.HttpServer; |
47 | using OpenSim.Framework.Client; | ||
48 | using OpenSim.Services.Interfaces; | 51 | using OpenSim.Services.Interfaces; |
49 | 52 | ||
50 | using Caps = OpenSim.Framework.Capabilities.Caps; | 53 | using Caps = OpenSim.Framework.Capabilities.Caps; |
@@ -55,14 +58,16 @@ using PermissionMask = OpenSim.Framework.PermissionMask; | |||
55 | namespace OpenSim.Region.ClientStack.Linden | 58 | namespace OpenSim.Region.ClientStack.Linden |
56 | { | 59 | { |
57 | public delegate void UpLoadedAsset( | 60 | public delegate void UpLoadedAsset( |
58 | string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, | 61 | string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, |
59 | byte[] data, string inventoryType, string assetType); | 62 | byte[] data, string inventoryType, string assetType, |
63 | int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances, | ||
64 | bool IsAtestUpload, ref string error, ref int nextOwnerMask, ref int groupMask, ref int everyoneMask); | ||
60 | 65 | ||
61 | public delegate UUID UpdateItem(UUID itemID, byte[] data); | 66 | public delegate UUID UpdateItem(UUID itemID, byte[] data); |
62 | 67 | ||
63 | public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); | 68 | public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); |
64 | 69 | ||
65 | public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); | 70 | public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost); |
66 | 71 | ||
67 | public delegate void NewAsset(AssetBase asset); | 72 | public delegate void NewAsset(AssetBase asset); |
68 | 73 | ||
@@ -87,21 +92,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
87 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 92 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
88 | 93 | ||
89 | private Scene m_Scene; | 94 | private Scene m_Scene; |
95 | private UUID m_AgentID; | ||
90 | private Caps m_HostCapsObj; | 96 | private Caps m_HostCapsObj; |
97 | private ModelCost m_ModelCost; | ||
91 | 98 | ||
92 | private static readonly string m_requestPath = "0000/"; | ||
93 | // private static readonly string m_mapLayerPath = "0001/"; | ||
94 | private static readonly string m_newInventory = "0002/"; | ||
95 | //private static readonly string m_requestTexture = "0003/"; | ||
96 | private static readonly string m_notecardUpdatePath = "0004/"; | ||
97 | private static readonly string m_notecardTaskUpdatePath = "0005/"; | ||
98 | // private static readonly string m_fetchInventoryPath = "0006/"; | ||
99 | private static readonly string m_copyFromNotecardPath = "0007/"; | ||
100 | // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. | 99 | // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. |
101 | private static readonly string m_getObjectPhysicsDataPath = "0101/"; | 100 | |
102 | /* 0102 - 0103 RESERVED */ | ||
103 | private static readonly string m_UpdateAgentInformationPath = "0500/"; | ||
104 | |||
105 | // These are callbacks which will be setup by the scene so that we can update scene data when we | 101 | // These are callbacks which will be setup by the scene so that we can update scene data when we |
106 | // receive capability calls | 102 | // receive capability calls |
107 | public NewInventoryItem AddNewInventoryItem = null; | 103 | public NewInventoryItem AddNewInventoryItem = null; |
@@ -115,12 +111,45 @@ namespace OpenSim.Region.ClientStack.Linden | |||
115 | private IAssetService m_assetService; | 111 | private IAssetService m_assetService; |
116 | private bool m_dumpAssetsToFile = false; | 112 | private bool m_dumpAssetsToFile = false; |
117 | private string m_regionName; | 113 | private string m_regionName; |
114 | |||
118 | private int m_levelUpload = 0; | 115 | private int m_levelUpload = 0; |
119 | 116 | ||
120 | public BunchOfCaps(Scene scene, Caps caps) | 117 | private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack |
118 | private bool m_ForceFreeTestUpload = false; // forces all uploads to be test | ||
119 | |||
120 | private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory | ||
121 | // may not be visible till relog | ||
122 | |||
123 | private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!! | ||
124 | private UUID m_testAssetsCreatorID = UUID.Zero; | ||
125 | |||
126 | private float m_PrimScaleMin = 0.001f; | ||
127 | |||
128 | private bool m_AllowCapHomeLocation = true; | ||
129 | private bool m_AllowCapGroupMemberData = true; | ||
130 | private IUserManagement m_UserManager; | ||
131 | |||
132 | |||
133 | private enum FileAgentInventoryState : int | ||
134 | { | ||
135 | idle = 0, | ||
136 | processRequest = 1, | ||
137 | waitUpload = 2, | ||
138 | processUpload = 3 | ||
139 | } | ||
140 | private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle; | ||
141 | |||
142 | public BunchOfCaps(Scene scene, UUID agentID, Caps caps) | ||
121 | { | 143 | { |
122 | m_Scene = scene; | 144 | m_Scene = scene; |
145 | m_AgentID = agentID; | ||
123 | m_HostCapsObj = caps; | 146 | m_HostCapsObj = caps; |
147 | |||
148 | // create a model upload cost provider | ||
149 | m_ModelCost = new ModelCost(scene); | ||
150 | |||
151 | m_PrimScaleMin = m_ModelCost.PrimScaleMin; | ||
152 | |||
124 | IConfigSource config = m_Scene.Config; | 153 | IConfigSource config = m_Scene.Config; |
125 | if (config != null) | 154 | if (config != null) |
126 | { | 155 | { |
@@ -135,10 +164,45 @@ namespace OpenSim.Region.ClientStack.Linden | |||
135 | { | 164 | { |
136 | m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); | 165 | m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); |
137 | } | 166 | } |
167 | // economy for model upload | ||
168 | IConfig EconomyConfig = config.Configs["Economy"]; | ||
169 | if (EconomyConfig != null) | ||
170 | { | ||
171 | m_ModelCost.Econfig(EconomyConfig); | ||
172 | |||
173 | m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory); | ||
174 | |||
175 | m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms); | ||
176 | m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload); | ||
177 | m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload); | ||
178 | string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", ""); | ||
179 | if (testcreator != "") | ||
180 | { | ||
181 | UUID id; | ||
182 | UUID.TryParse(testcreator, out id); | ||
183 | if (id != null) | ||
184 | m_testAssetsCreatorID = id; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | IConfig CapsConfig = config.Configs["ClientStack.LindenCaps"]; | ||
189 | if (CapsConfig != null) | ||
190 | { | ||
191 | string homeLocationUrl = CapsConfig.GetString("Cap_HomeLocation", "localhost"); | ||
192 | if(homeLocationUrl == String.Empty) | ||
193 | m_AllowCapHomeLocation = false; | ||
194 | |||
195 | string GroupMemberDataUrl = CapsConfig.GetString("Cap_GroupMemberData", "localhost"); | ||
196 | if(GroupMemberDataUrl == String.Empty) | ||
197 | m_AllowCapGroupMemberData = false; | ||
198 | } | ||
138 | } | 199 | } |
139 | 200 | ||
140 | m_assetService = m_Scene.AssetService; | 201 | m_assetService = m_Scene.AssetService; |
141 | m_regionName = m_Scene.RegionInfo.RegionName; | 202 | m_regionName = m_Scene.RegionInfo.RegionName; |
203 | m_UserManager = m_Scene.RequestModuleInterface<IUserManagement>(); | ||
204 | if (m_UserManager == null) | ||
205 | m_log.Error("[CAPS]: GetDisplayNames disabled because user management component not found"); | ||
142 | 206 | ||
143 | RegisterHandlers(); | 207 | RegisterHandlers(); |
144 | 208 | ||
@@ -146,6 +210,13 @@ namespace OpenSim.Region.ClientStack.Linden | |||
146 | ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; | 210 | ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; |
147 | TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; | 211 | TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; |
148 | GetClient = m_Scene.SceneGraph.GetControllingClient; | 212 | GetClient = m_Scene.SceneGraph.GetControllingClient; |
213 | |||
214 | m_FileAgentInventoryState = FileAgentInventoryState.idle; | ||
215 | } | ||
216 | |||
217 | public string GetNewCapPath() | ||
218 | { | ||
219 | return "/CAPS/" + UUID.Random(); | ||
149 | } | 220 | } |
150 | 221 | ||
151 | /// <summary> | 222 | /// <summary> |
@@ -153,33 +224,67 @@ namespace OpenSim.Region.ClientStack.Linden | |||
153 | /// </summary> | 224 | /// </summary> |
154 | public void RegisterHandlers() | 225 | public void RegisterHandlers() |
155 | { | 226 | { |
156 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | 227 | // this path is also defined elsewhere so keeping it |
228 | string seedcapsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath +"0000/"; | ||
157 | 229 | ||
158 | RegisterRegionServiceHandlers(capsBase); | 230 | // the root of all evil path needs to be capsBase + m_requestPath |
159 | RegisterInventoryServiceHandlers(capsBase); | 231 | m_HostCapsObj.RegisterHandler( |
232 | "SEED", new RestStreamHandler("POST", seedcapsBase, SeedCapRequest, "SEED", null)); | ||
233 | |||
234 | // m_log.DebugFormat( | ||
235 | // "[CAPS]: Registered seed capability {0} for {1}", seedcapsBase, m_HostCapsObj.AgentID); | ||
236 | |||
237 | RegisterRegionServiceHandlers(); | ||
238 | RegisterInventoryServiceHandlers(); | ||
239 | RegisterOtherHandlers(); | ||
160 | } | 240 | } |
161 | 241 | ||
162 | public void RegisterRegionServiceHandlers(string capsBase) | 242 | public void RegisterRegionServiceHandlers() |
163 | { | 243 | { |
164 | try | 244 | try |
165 | { | 245 | { |
166 | // the root of all evil | ||
167 | m_HostCapsObj.RegisterHandler( | ||
168 | "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null)); | ||
169 | |||
170 | // m_log.DebugFormat( | ||
171 | // "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID); | ||
172 | |||
173 | //m_capsHandlers["MapLayer"] = | 246 | //m_capsHandlers["MapLayer"] = |
174 | // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", | 247 | // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", |
175 | // capsBase + m_mapLayerPath, | 248 | // GetNewCapPath(), |
176 | // GetMapLayer); | 249 | // GetMapLayer); |
177 | IRequestHandler req | 250 | |
178 | = new RestStreamHandler( | 251 | IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler( |
179 | "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null); | 252 | "POST", GetNewCapPath(), GetObjectPhysicsData, "GetObjectPhysicsData", null); |
253 | m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); | ||
254 | |||
255 | IRequestHandler getObjectCostHandler = new RestStreamHandler( | ||
256 | "POST", GetNewCapPath(), GetObjectCost, "GetObjectCost", null ); | ||
257 | m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler); | ||
180 | 258 | ||
259 | IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler( | ||
260 | "POST", GetNewCapPath(), ResourceCostSelected, "ResourceCostSelected", null); | ||
261 | m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); | ||
262 | |||
263 | IRequestHandler req = new RestStreamHandler( | ||
264 | "POST", GetNewCapPath(), ScriptTaskInventory, "UpdateScript", null); | ||
181 | m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req); | 265 | m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req); |
182 | m_HostCapsObj.RegisterHandler("UpdateScriptTask", req); | 266 | m_HostCapsObj.RegisterHandler("UpdateScriptTask", req); |
267 | |||
268 | if(m_AllowCapHomeLocation) | ||
269 | { | ||
270 | IRequestHandler HomeLocationHandler = new RestStreamHandler( | ||
271 | "POST", GetNewCapPath(), HomeLocation, "HomeLocation", null); | ||
272 | m_HostCapsObj.RegisterHandler("HomeLocation", HomeLocationHandler); | ||
273 | } | ||
274 | |||
275 | if(m_AllowCapGroupMemberData) | ||
276 | { | ||
277 | IRequestHandler GroupMemberDataHandler = new RestStreamHandler( | ||
278 | "POST", GetNewCapPath(), GroupMemberData, "GroupMemberData", null); | ||
279 | m_HostCapsObj.RegisterHandler("GroupMemberData", GroupMemberDataHandler); | ||
280 | } | ||
281 | |||
282 | |||
283 | // IRequestHandler animSetRequestHandler | ||
284 | // = new RestStreamHandler( | ||
285 | // "POST", capsBase + m_animSetTaskUpdatePath, AnimSetTaskInventory, "UpdateScript", null); | ||
286 | |||
287 | // m_HostCapsObj.RegisterHandler("UpdateAnimSetTaskInventory", animSetRequestHandler); | ||
183 | } | 288 | } |
184 | catch (Exception e) | 289 | catch (Exception e) |
185 | { | 290 | { |
@@ -187,68 +292,29 @@ namespace OpenSim.Region.ClientStack.Linden | |||
187 | } | 292 | } |
188 | } | 293 | } |
189 | 294 | ||
190 | public void RegisterInventoryServiceHandlers(string capsBase) | 295 | public void RegisterInventoryServiceHandlers() |
191 | { | 296 | { |
192 | try | 297 | try |
193 | { | 298 | { |
194 | // I don't think this one works... | 299 | m_HostCapsObj.RegisterHandler("NewFileAgentInventory", |
195 | m_HostCapsObj.RegisterHandler( | ||
196 | "NewFileAgentInventory", | ||
197 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( | 300 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( |
198 | "POST", | 301 | "POST", GetNewCapPath(), NewAgentInventoryRequest, "NewFileAgentInventory", null)); |
199 | capsBase + m_newInventory, | ||
200 | NewAgentInventoryRequest, | ||
201 | "NewFileAgentInventory", | ||
202 | null)); | ||
203 | |||
204 | IRequestHandler req | ||
205 | = new RestStreamHandler( | ||
206 | "POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null); | ||
207 | 302 | ||
303 | IRequestHandler req = new RestStreamHandler( | ||
304 | "POST", GetNewCapPath(), NoteCardAgentInventory, "Update*", null); | ||
208 | m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); | 305 | m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); |
306 | m_HostCapsObj.RegisterHandler("UpdateAnimSetAgentInventory", req); | ||
209 | m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); | 307 | m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); |
210 | m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); | 308 | m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); |
211 | 309 | ||
212 | IRequestHandler getObjectPhysicsDataHandler | 310 | IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler( |
213 | = new RestStreamHandler( | 311 | "POST", GetNewCapPath(), UpdateAgentInformation, "UpdateAgentInformation", null); |
214 | "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null); | ||
215 | m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); | ||
216 | |||
217 | IRequestHandler UpdateAgentInformationHandler | ||
218 | = new RestStreamHandler( | ||
219 | "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null); | ||
220 | m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); | 312 | m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); |
221 | 313 | ||
222 | m_HostCapsObj.RegisterHandler( | 314 | IRequestHandler CopyInventoryFromNotecardHandler = new RestStreamHandler( |
223 | "CopyInventoryFromNotecard", | 315 | "POST", GetNewCapPath(), CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null); |
224 | new RestStreamHandler( | 316 | m_HostCapsObj.RegisterHandler("CopyInventoryFromNotecard", CopyInventoryFromNotecardHandler); |
225 | "POST", capsBase + m_copyFromNotecardPath, CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null)); | 317 | |
226 | |||
227 | // As of RC 1.22.9 of the Linden client this is | ||
228 | // supported | ||
229 | |||
230 | //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest); | ||
231 | |||
232 | // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and | ||
233 | // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires | ||
234 | // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service, | ||
235 | // but when I went on the Linden grid, the | ||
236 | // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead, | ||
237 | // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP | ||
238 | // | ||
239 | // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid | ||
240 | // we will be | ||
241 | // able to get the data we need to implement the necessary part of the protocol to fix the issue above. | ||
242 | // m_capsHandlers["FetchInventoryDescendents"] = | ||
243 | // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest); | ||
244 | |||
245 | // m_capsHandlers["FetchInventoryDescendents"] = | ||
246 | // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST", | ||
247 | // capsBase + m_fetchInventory, | ||
248 | // FetchInventory)); | ||
249 | // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST", | ||
250 | // capsBase + m_requestTexture, | ||
251 | // RequestTexture); | ||
252 | } | 318 | } |
253 | catch (Exception e) | 319 | catch (Exception e) |
254 | { | 320 | { |
@@ -256,6 +322,22 @@ namespace OpenSim.Region.ClientStack.Linden | |||
256 | } | 322 | } |
257 | } | 323 | } |
258 | 324 | ||
325 | public void RegisterOtherHandlers() | ||
326 | { | ||
327 | try | ||
328 | { | ||
329 | if (m_UserManager != null) | ||
330 | { | ||
331 | IRequestHandler GetDisplayNamesHandler = new RestStreamHandler( | ||
332 | "GET", GetNewCapPath(), GetDisplayNames, "GetDisplayNames", null); | ||
333 | m_HostCapsObj.RegisterHandler("GetDisplayNames", GetDisplayNamesHandler); | ||
334 | } | ||
335 | } | ||
336 | catch (Exception e) | ||
337 | { | ||
338 | m_log.Error("[CAPS]: " + e.ToString()); | ||
339 | } | ||
340 | } | ||
259 | /// <summary> | 341 | /// <summary> |
260 | /// Construct a client response detailing all the capabilities this server can provide. | 342 | /// Construct a client response detailing all the capabilities this server can provide. |
261 | /// </summary> | 343 | /// </summary> |
@@ -268,8 +350,11 @@ namespace OpenSim.Region.ClientStack.Linden | |||
268 | public string SeedCapRequest(string request, string path, string param, | 350 | public string SeedCapRequest(string request, string path, string param, |
269 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 351 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
270 | { | 352 | { |
271 | // m_log.DebugFormat( | 353 | m_log.DebugFormat( |
272 | // "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); | 354 | "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); |
355 | |||
356 | if (!m_HostCapsObj.WaitForActivation()) | ||
357 | return string.Empty; | ||
273 | 358 | ||
274 | if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) | 359 | if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) |
275 | { | 360 | { |
@@ -314,30 +399,28 @@ namespace OpenSim.Region.ClientStack.Linden | |||
314 | LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate(); | 399 | LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate(); |
315 | LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest); | 400 | LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest); |
316 | 401 | ||
317 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | 402 | string uploaderPath = GetNewCapPath(); |
318 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
319 | 403 | ||
320 | TaskInventoryScriptUpdater uploader = | 404 | TaskInventoryScriptUpdater uploader = |
321 | new TaskInventoryScriptUpdater( | 405 | new TaskInventoryScriptUpdater( |
322 | llsdUpdateRequest.item_id, | 406 | llsdUpdateRequest.item_id, |
323 | llsdUpdateRequest.task_id, | 407 | llsdUpdateRequest.task_id, |
324 | llsdUpdateRequest.is_script_running, | 408 | llsdUpdateRequest.is_script_running, |
325 | capsBase + uploaderPath, | 409 | uploaderPath, |
326 | m_HostCapsObj.HttpListener, | 410 | m_HostCapsObj.HttpListener, |
327 | m_dumpAssetsToFile); | 411 | m_dumpAssetsToFile); |
328 | uploader.OnUpLoad += TaskScriptUpdated; | 412 | uploader.OnUpLoad += TaskScriptUpdated; |
329 | 413 | ||
330 | m_HostCapsObj.HttpListener.AddStreamHandler( | 414 | m_HostCapsObj.HttpListener.AddStreamHandler( |
331 | new BinaryStreamHandler( | 415 | new BinaryStreamHandler( |
332 | "POST", capsBase + uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null)); | 416 | "POST", uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null)); |
333 | 417 | ||
334 | string protocol = "http://"; | 418 | string protocol = "http://"; |
335 | 419 | ||
336 | if (m_HostCapsObj.SSLCaps) | 420 | if (m_HostCapsObj.SSLCaps) |
337 | protocol = "https://"; | 421 | protocol = "https://"; |
338 | 422 | ||
339 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + | 423 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath; |
340 | uploaderPath; | ||
341 | 424 | ||
342 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | 425 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); |
343 | uploadResponse.uploader = uploaderURL; | 426 | uploadResponse.uploader = uploaderURL; |
@@ -400,83 +483,208 @@ namespace OpenSim.Region.ClientStack.Linden | |||
400 | //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); | 483 | //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); |
401 | //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); | 484 | //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); |
402 | 485 | ||
486 | // start by getting the client | ||
487 | IClientAPI client = null; | ||
488 | m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); | ||
489 | |||
490 | // check current state so we only have one service at a time | ||
491 | lock (m_ModelCost) | ||
492 | { | ||
493 | switch (m_FileAgentInventoryState) | ||
494 | { | ||
495 | case FileAgentInventoryState.processRequest: | ||
496 | case FileAgentInventoryState.processUpload: | ||
497 | LLSDAssetUploadError resperror = new LLSDAssetUploadError(); | ||
498 | resperror.message = "Uploader busy processing previus request"; | ||
499 | resperror.identifier = UUID.Zero; | ||
500 | |||
501 | LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); | ||
502 | errorResponse.uploader = ""; | ||
503 | errorResponse.state = "error"; | ||
504 | errorResponse.error = resperror; | ||
505 | return errorResponse; | ||
506 | // break; | ||
507 | case FileAgentInventoryState.waitUpload: | ||
508 | // todo stop current uploader server | ||
509 | break; | ||
510 | case FileAgentInventoryState.idle: | ||
511 | default: | ||
512 | break; | ||
513 | } | ||
514 | |||
515 | m_FileAgentInventoryState = FileAgentInventoryState.processRequest; | ||
516 | } | ||
517 | |||
518 | int cost = 0; | ||
519 | int nreqtextures = 0; | ||
520 | int nreqmeshs= 0; | ||
521 | int nreqinstances = 0; | ||
522 | bool IsAtestUpload = false; | ||
523 | |||
524 | string assetName = llsdRequest.name; | ||
525 | |||
526 | LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData(); | ||
527 | |||
403 | if (llsdRequest.asset_type == "texture" || | 528 | if (llsdRequest.asset_type == "texture" || |
404 | llsdRequest.asset_type == "animation" || | 529 | llsdRequest.asset_type == "animation" || |
530 | llsdRequest.asset_type == "animatn" || // this is the asset name actually used by viewers | ||
531 | llsdRequest.asset_type == "mesh" || | ||
405 | llsdRequest.asset_type == "sound") | 532 | llsdRequest.asset_type == "sound") |
406 | { | 533 | { |
407 | ScenePresence avatar = null; | 534 | ScenePresence avatar = null; |
408 | IClientAPI client = null; | ||
409 | m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); | 535 | m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); |
410 | 536 | ||
411 | // check user level | 537 | // check user level |
412 | if (avatar != null) | 538 | if (avatar != null) |
413 | { | 539 | { |
414 | client = avatar.ControllingClient; | 540 | if (avatar.GodController.UserLevel < m_levelUpload) |
415 | |||
416 | if (avatar.UserLevel < m_levelUpload) | ||
417 | { | 541 | { |
418 | if (client != null) | 542 | LLSDAssetUploadError resperror = new LLSDAssetUploadError(); |
419 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); | 543 | resperror.message = "Insufficient permissions to upload"; |
544 | resperror.identifier = UUID.Zero; | ||
420 | 545 | ||
421 | LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); | 546 | LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); |
422 | errorResponse.uploader = ""; | 547 | errorResponse.uploader = ""; |
423 | errorResponse.state = "error"; | 548 | errorResponse.state = "error"; |
549 | errorResponse.error = resperror; | ||
550 | lock (m_ModelCost) | ||
551 | m_FileAgentInventoryState = FileAgentInventoryState.idle; | ||
424 | return errorResponse; | 552 | return errorResponse; |
425 | } | 553 | } |
426 | } | 554 | } |
427 | 555 | ||
428 | // check funds | 556 | // check test upload and funds |
429 | if (client != null) | 557 | if (client != null) |
430 | { | 558 | { |
431 | IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); | 559 | IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); |
432 | 560 | ||
561 | int baseCost = 0; | ||
433 | if (mm != null) | 562 | if (mm != null) |
563 | baseCost = mm.UploadCharge; | ||
564 | |||
565 | string warning = String.Empty; | ||
566 | |||
567 | if (llsdRequest.asset_type == "mesh") | ||
434 | { | 568 | { |
435 | if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) | 569 | string error; |
570 | int modelcost; | ||
571 | |||
572 | |||
573 | if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost, | ||
574 | meshcostdata, out error, ref warning)) | ||
436 | { | 575 | { |
437 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); | 576 | LLSDAssetUploadError resperror = new LLSDAssetUploadError(); |
577 | resperror.message = error; | ||
578 | resperror.identifier = UUID.Zero; | ||
438 | 579 | ||
439 | LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); | 580 | LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); |
440 | errorResponse.uploader = ""; | 581 | errorResponse.uploader = ""; |
441 | errorResponse.state = "error"; | 582 | errorResponse.state = "error"; |
583 | errorResponse.error = resperror; | ||
584 | |||
585 | lock (m_ModelCost) | ||
586 | m_FileAgentInventoryState = FileAgentInventoryState.idle; | ||
442 | return errorResponse; | 587 | return errorResponse; |
443 | } | 588 | } |
589 | cost = modelcost; | ||
444 | } | 590 | } |
591 | else | ||
592 | { | ||
593 | cost = baseCost; | ||
594 | } | ||
595 | |||
596 | if (cost > 0 && mm != null) | ||
597 | { | ||
598 | // check for test upload | ||
599 | |||
600 | if (m_ForceFreeTestUpload) // all are test | ||
601 | { | ||
602 | if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it | ||
603 | assetName = "TEST-" + assetName; | ||
604 | |||
605 | IsAtestUpload = true; | ||
606 | } | ||
607 | |||
608 | else if (m_enableFreeTestUpload) // only if prefixed with "TEST-" | ||
609 | { | ||
610 | |||
611 | IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-")); | ||
612 | } | ||
613 | |||
614 | |||
615 | if(IsAtestUpload) // let user know, still showing cost estimation | ||
616 | warning += "Upload will have no cost, for testing purposes only. Other uses are prohibited. Items will not work after 48 hours or on other regions"; | ||
617 | |||
618 | // check funds | ||
619 | else | ||
620 | { | ||
621 | if (!mm.UploadCovered(client.AgentId, (int)cost)) | ||
622 | { | ||
623 | LLSDAssetUploadError resperror = new LLSDAssetUploadError(); | ||
624 | resperror.message = "Insuficient funds"; | ||
625 | resperror.identifier = UUID.Zero; | ||
626 | |||
627 | LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); | ||
628 | errorResponse.uploader = ""; | ||
629 | errorResponse.state = "error"; | ||
630 | errorResponse.error = resperror; | ||
631 | lock (m_ModelCost) | ||
632 | m_FileAgentInventoryState = FileAgentInventoryState.idle; | ||
633 | return errorResponse; | ||
634 | } | ||
635 | } | ||
636 | } | ||
637 | |||
638 | if (client != null && warning != String.Empty) | ||
639 | client.SendAgentAlertMessage(warning, true); | ||
445 | } | 640 | } |
446 | } | 641 | } |
447 | 642 | ||
448 | string assetName = llsdRequest.name; | ||
449 | string assetDes = llsdRequest.description; | 643 | string assetDes = llsdRequest.description; |
450 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||
451 | UUID newAsset = UUID.Random(); | 644 | UUID newAsset = UUID.Random(); |
452 | UUID newInvItem = UUID.Random(); | 645 | UUID newInvItem = UUID.Random(); |
453 | UUID parentFolder = llsdRequest.folder_id; | 646 | UUID parentFolder = llsdRequest.folder_id; |
454 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | 647 | string uploaderPath = GetNewCapPath(); |
648 | UUID texturesFolder = UUID.Zero; | ||
649 | |||
650 | if(!IsAtestUpload && m_enableModelUploadTextureToInventory) | ||
651 | texturesFolder = llsdRequest.texture_folder_id; | ||
455 | 652 | ||
456 | AssetUploader uploader = | 653 | AssetUploader uploader = |
457 | new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, | 654 | new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, |
458 | llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); | 655 | llsdRequest.asset_type, uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost, |
656 | texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload, | ||
657 | llsdRequest.next_owner_mask, llsdRequest.group_mask, llsdRequest.everyone_mask); | ||
459 | 658 | ||
460 | m_HostCapsObj.HttpListener.AddStreamHandler( | 659 | m_HostCapsObj.HttpListener.AddStreamHandler( |
461 | new BinaryStreamHandler( | 660 | new BinaryStreamHandler( |
462 | "POST", | 661 | "POST", |
463 | capsBase + uploaderPath, | 662 | uploaderPath, |
464 | uploader.uploaderCaps, | 663 | uploader.uploaderCaps, |
465 | "NewAgentInventoryRequest", | 664 | "NewAgentInventoryRequest", |
466 | m_HostCapsObj.AgentID.ToString())); | 665 | m_HostCapsObj.AgentID.ToString())); |
467 | 666 | ||
468 | string protocol = "http://"; | 667 | string protocol = "http://"; |
469 | |||
470 | if (m_HostCapsObj.SSLCaps) | 668 | if (m_HostCapsObj.SSLCaps) |
471 | protocol = "https://"; | 669 | protocol = "https://"; |
472 | 670 | ||
473 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + | 671 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath; |
474 | uploaderPath; | ||
475 | 672 | ||
476 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | 673 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); |
477 | uploadResponse.uploader = uploaderURL; | 674 | uploadResponse.uploader = uploaderURL; |
478 | uploadResponse.state = "upload"; | 675 | uploadResponse.state = "upload"; |
676 | uploadResponse.upload_price = (int)cost; | ||
677 | |||
678 | if (llsdRequest.asset_type == "mesh") | ||
679 | { | ||
680 | uploadResponse.data = meshcostdata; | ||
681 | } | ||
682 | |||
479 | uploader.OnUpLoad += UploadCompleteHandler; | 683 | uploader.OnUpLoad += UploadCompleteHandler; |
684 | |||
685 | lock (m_ModelCost) | ||
686 | m_FileAgentInventoryState = FileAgentInventoryState.waitUpload; | ||
687 | |||
480 | return uploadResponse; | 688 | return uploadResponse; |
481 | } | 689 | } |
482 | 690 | ||
@@ -488,8 +696,14 @@ namespace OpenSim.Region.ClientStack.Linden | |||
488 | /// <param name="data"></param> | 696 | /// <param name="data"></param> |
489 | public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, | 697 | public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, |
490 | UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, | 698 | UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, |
491 | string assetType) | 699 | string assetType, int cost, |
700 | UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances, | ||
701 | bool IsAtestUpload, ref string error, | ||
702 | ref int nextOwnerMask, ref int groupMask, ref int everyoneMask) | ||
492 | { | 703 | { |
704 | lock (m_ModelCost) | ||
705 | m_FileAgentInventoryState = FileAgentInventoryState.processUpload; | ||
706 | |||
493 | m_log.DebugFormat( | 707 | m_log.DebugFormat( |
494 | "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", | 708 | "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", |
495 | assetID, inventoryItem, inventoryType, assetType); | 709 | assetID, inventoryItem, inventoryType, assetType); |
@@ -497,6 +711,34 @@ namespace OpenSim.Region.ClientStack.Linden | |||
497 | sbyte assType = 0; | 711 | sbyte assType = 0; |
498 | sbyte inType = 0; | 712 | sbyte inType = 0; |
499 | 713 | ||
714 | IClientAPI client = null; | ||
715 | |||
716 | UUID owner_id = m_HostCapsObj.AgentID; | ||
717 | UUID creatorID; | ||
718 | |||
719 | bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0); | ||
720 | |||
721 | bool restrictPerms = m_RestrictFreeTestUploadPerms && istest; | ||
722 | |||
723 | if (istest && m_testAssetsCreatorID != UUID.Zero) | ||
724 | creatorID = m_testAssetsCreatorID; | ||
725 | else | ||
726 | creatorID = owner_id; | ||
727 | |||
728 | string creatorIDstr = creatorID.ToString(); | ||
729 | |||
730 | IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); | ||
731 | if (mm != null) | ||
732 | { | ||
733 | // make sure client still has enougth credit | ||
734 | if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost)) | ||
735 | { | ||
736 | error = "Insufficient funds."; | ||
737 | return; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | // strings to types | ||
500 | if (inventoryType == "sound") | 742 | if (inventoryType == "sound") |
501 | { | 743 | { |
502 | inType = (sbyte)InventoryType.Sound; | 744 | inType = (sbyte)InventoryType.Sound; |
@@ -511,6 +753,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
511 | inType = (sbyte)InventoryType.Animation; | 753 | inType = (sbyte)InventoryType.Animation; |
512 | assType = (sbyte)AssetType.Animation; | 754 | assType = (sbyte)AssetType.Animation; |
513 | } | 755 | } |
756 | else if (inventoryType == "animset") | ||
757 | { | ||
758 | inType = (sbyte)CustomInventoryType.AnimationSet; | ||
759 | assType = (sbyte)CustomAssetType.AnimationSet; | ||
760 | m_log.Debug("got animset upload request"); | ||
761 | } | ||
514 | else if (inventoryType == "wearable") | 762 | else if (inventoryType == "wearable") |
515 | { | 763 | { |
516 | inType = (sbyte)InventoryType.Wearable; | 764 | inType = (sbyte)InventoryType.Wearable; |
@@ -526,191 +774,290 @@ namespace OpenSim.Region.ClientStack.Linden | |||
526 | } | 774 | } |
527 | else if (inventoryType == "object") | 775 | else if (inventoryType == "object") |
528 | { | 776 | { |
529 | inType = (sbyte)InventoryType.Object; | 777 | if (assetType == "mesh") // this code for now is for mesh models uploads only |
530 | assType = (sbyte)AssetType.Object; | 778 | { |
531 | 779 | inType = (sbyte)InventoryType.Object; | |
532 | List<Vector3> positions = new List<Vector3>(); | 780 | assType = (sbyte)AssetType.Object; |
533 | List<Quaternion> rotations = new List<Quaternion>(); | ||
534 | OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data); | ||
535 | OSDArray instance_list = (OSDArray)request["instance_list"]; | ||
536 | OSDArray mesh_list = (OSDArray)request["mesh_list"]; | ||
537 | OSDArray texture_list = (OSDArray)request["texture_list"]; | ||
538 | SceneObjectGroup grp = null; | ||
539 | 781 | ||
540 | InventoryFolderBase textureUploadFolder = null; | 782 | List<Vector3> positions = new List<Vector3>(); |
783 | List<Quaternion> rotations = new List<Quaternion>(); | ||
784 | OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data); | ||
541 | 785 | ||
542 | List<InventoryFolderBase> foldersToUpdate = new List<InventoryFolderBase>(); | 786 | // compare and get updated information |
543 | List<InventoryItemBase> itemsToUpdate = new List<InventoryItemBase>(); | 787 | /* does nothing still we do need something to avoid special viewer to upload something diferent from the cost estimation |
544 | IClientInventory clientInv = null; | 788 | bool mismatchError = true; |
545 | |||
546 | if (texture_list.Count > 0) | ||
547 | { | ||
548 | ScenePresence avatar = null; | ||
549 | m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); | ||
550 | 789 | ||
551 | if (avatar != null) | 790 | while (mismatchError) |
552 | { | 791 | { |
553 | IClientCore core = (IClientCore)avatar.ControllingClient; | 792 | mismatchError = false; |
793 | } | ||
794 | |||
795 | if (mismatchError) | ||
796 | { | ||
797 | error = "Upload and fee estimation information don't match"; | ||
798 | lock (m_ModelCost) | ||
799 | m_FileAgentInventoryState = FileAgentInventoryState.idle; | ||
800 | |||
801 | return; | ||
802 | } | ||
803 | */ | ||
804 | OSDArray instance_list = (OSDArray)request["instance_list"]; | ||
805 | OSDArray mesh_list = (OSDArray)request["mesh_list"]; | ||
806 | OSDArray texture_list = (OSDArray)request["texture_list"]; | ||
807 | SceneObjectGroup grp = null; | ||
554 | 808 | ||
555 | if (core.TryGet<IClientInventory>(out clientInv)) | 809 | // create and store texture assets |
810 | bool doTextInv = (!istest && m_enableModelUploadTextureToInventory && | ||
811 | texturesFolder != UUID.Zero); | ||
812 | |||
813 | |||
814 | List<UUID> textures = new List<UUID>(); | ||
815 | |||
816 | |||
817 | // if (doTextInv) | ||
818 | m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); | ||
819 | |||
820 | if(client == null) // don't put textures in inventory if there is no client | ||
821 | doTextInv = false; | ||
822 | |||
823 | for (int i = 0; i < texture_list.Count; i++) | ||
824 | { | ||
825 | AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr); | ||
826 | textureAsset.Data = texture_list[i].AsBinary(); | ||
827 | if (istest) | ||
828 | textureAsset.Local = true; | ||
829 | m_assetService.Store(textureAsset); | ||
830 | textures.Add(textureAsset.FullID); | ||
831 | |||
832 | if (doTextInv) | ||
556 | { | 833 | { |
557 | var systemTextureFolder = m_Scene.InventoryService.GetFolderForType(m_HostCapsObj.AgentID, FolderType.Texture); | 834 | string name = assetName; |
558 | textureUploadFolder = new InventoryFolderBase(UUID.Random(), assetName, m_HostCapsObj.AgentID, (short)FolderType.None, systemTextureFolder.ID, 1); | 835 | if (name.Length > 25) |
559 | if (m_Scene.InventoryService.AddFolder(textureUploadFolder)) | 836 | name = name.Substring(0, 24); |
560 | { | 837 | name += "_Texture#" + i.ToString(); |
561 | foldersToUpdate.Add(textureUploadFolder); | 838 | InventoryItemBase texitem = new InventoryItemBase(); |
839 | texitem.Owner = m_HostCapsObj.AgentID; | ||
840 | texitem.CreatorId = creatorIDstr; | ||
841 | texitem.CreatorData = String.Empty; | ||
842 | texitem.ID = UUID.Random(); | ||
843 | texitem.AssetID = textureAsset.FullID; | ||
844 | texitem.Description = "mesh model texture"; | ||
845 | texitem.Name = name; | ||
846 | texitem.AssetType = (int)AssetType.Texture; | ||
847 | texitem.InvType = (int)InventoryType.Texture; | ||
848 | texitem.Folder = texturesFolder; | ||
849 | |||
850 | texitem.CurrentPermissions | ||
851 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export); | ||
852 | |||
853 | texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; | ||
854 | texitem.EveryOnePermissions = 0; | ||
855 | texitem.NextPermissions = (uint)PermissionMask.All; | ||
856 | texitem.CreationDate = Util.UnixTimeSinceEpoch(); | ||
857 | |||
858 | m_Scene.AddInventoryItem(client, texitem); | ||
859 | texitem = null; | ||
860 | } | ||
861 | } | ||
562 | 862 | ||
563 | m_log.DebugFormat( | 863 | // create and store meshs assets |
564 | "[BUNCH OF CAPS]: Created new folder '{0}' ({1}) for textures uploaded with mesh object {2}", | 864 | List<UUID> meshAssets = new List<UUID>(); |
565 | textureUploadFolder.Name, textureUploadFolder.ID, assetName); | 865 | List<bool> meshAvatarSkeletons = new List<bool>(); |
566 | } | 866 | List<bool> meshAvatarColliders = new List<bool>(); |
567 | else | 867 | |
868 | bool curAvSkeleton; | ||
869 | bool curAvCollider; | ||
870 | for (int i = 0; i < mesh_list.Count; i++) | ||
871 | { | ||
872 | curAvSkeleton = false; | ||
873 | curAvCollider = false; | ||
874 | |||
875 | // we do need to parse the mesh now | ||
876 | OSD osd = OSDParser.DeserializeLLSDBinary(mesh_list[i]); | ||
877 | if (osd is OSDMap) | ||
878 | { | ||
879 | OSDMap mosd = (OSDMap)osd; | ||
880 | if (mosd.ContainsKey("skeleton")) | ||
568 | { | 881 | { |
569 | textureUploadFolder = null; | 882 | OSDMap skeleton = (OSDMap)mosd["skeleton"]; |
883 | int sksize = skeleton["size"].AsInteger(); | ||
884 | if (sksize > 0) | ||
885 | curAvSkeleton = true; | ||
570 | } | 886 | } |
571 | } | 887 | } |
572 | } | ||
573 | } | ||
574 | 888 | ||
575 | List<UUID> textures = new List<UUID>(); | 889 | AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr); |
576 | for (int i = 0; i < texture_list.Count; i++) | 890 | meshAsset.Data = mesh_list[i].AsBinary(); |
577 | { | 891 | if (istest) |
578 | AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); | 892 | meshAsset.Local = true; |
579 | textureAsset.Data = texture_list[i].AsBinary(); | 893 | m_assetService.Store(meshAsset); |
580 | m_assetService.Store(textureAsset); | 894 | meshAssets.Add(meshAsset.FullID); |
581 | textures.Add(textureAsset.FullID); | 895 | meshAvatarSkeletons.Add(curAvSkeleton); |
896 | meshAvatarColliders.Add(curAvCollider); | ||
897 | |||
898 | // test code | ||
899 | if (curAvSkeleton && client != null) | ||
900 | { | ||
901 | string name = assetName; | ||
902 | if (name.Length > 25) | ||
903 | name = name.Substring(0, 24); | ||
904 | name += "_Mesh#" + i.ToString(); | ||
905 | InventoryItemBase meshitem = new InventoryItemBase(); | ||
906 | meshitem.Owner = m_HostCapsObj.AgentID; | ||
907 | meshitem.CreatorId = creatorIDstr; | ||
908 | meshitem.CreatorData = String.Empty; | ||
909 | meshitem.ID = UUID.Random(); | ||
910 | meshitem.AssetID = meshAsset.FullID; | ||
911 | meshitem.Description = "mesh "; | ||
912 | meshitem.Name = name; | ||
913 | meshitem.AssetType = (int)AssetType.Mesh; | ||
914 | meshitem.InvType = (int)InventoryType.Mesh; | ||
915 | // meshitem.Folder = UUID.Zero; // send to default | ||
916 | |||
917 | meshitem.Folder = parentFolder; // dont let it go to folder Meshes that viewers dont show | ||
918 | |||
919 | // If we set PermissionMask.All then when we rez the item the next permissions will replace the current | ||
920 | // (owner) permissions. This becomes a problem if next permissions are changed. | ||
921 | meshitem.CurrentPermissions | ||
922 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer); | ||
923 | |||
924 | meshitem.BasePermissions = (uint)PermissionMask.All; | ||
925 | meshitem.EveryOnePermissions = 0; | ||
926 | meshitem.NextPermissions = (uint)PermissionMask.All; | ||
927 | meshitem.CreationDate = Util.UnixTimeSinceEpoch(); | ||
928 | |||
929 | m_Scene.AddInventoryItem(client, meshitem); | ||
930 | meshitem = null; | ||
931 | } | ||
932 | } | ||
582 | 933 | ||
583 | if (textureUploadFolder != null) | 934 | int skipedMeshs = 0; |
935 | // build prims from instances | ||
936 | for (int i = 0; i < instance_list.Count; i++) | ||
584 | { | 937 | { |
585 | InventoryItemBase textureItem = new InventoryItemBase(); | 938 | OSDMap inner_instance_list = (OSDMap)instance_list[i]; |
586 | textureItem.Owner = m_HostCapsObj.AgentID; | ||
587 | textureItem.CreatorId = m_HostCapsObj.AgentID.ToString(); | ||
588 | textureItem.CreatorData = String.Empty; | ||
589 | textureItem.ID = UUID.Random(); | ||
590 | textureItem.AssetID = textureAsset.FullID; | ||
591 | textureItem.Description = assetDescription; | ||
592 | textureItem.Name = assetName + " - Texture " + (i + 1).ToString(); | ||
593 | textureItem.AssetType = (int)AssetType.Texture; | ||
594 | textureItem.InvType = (int)InventoryType.Texture; | ||
595 | textureItem.Folder = textureUploadFolder.ID; | ||
596 | textureItem.CurrentPermissions | ||
597 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export); | ||
598 | textureItem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; | ||
599 | textureItem.EveryOnePermissions = 0; | ||
600 | textureItem.NextPermissions = (uint)PermissionMask.All; | ||
601 | textureItem.CreationDate = Util.UnixTimeSinceEpoch(); | ||
602 | m_Scene.InventoryService.AddItem(textureItem); | ||
603 | itemsToUpdate.Add(textureItem); | ||
604 | |||
605 | m_log.DebugFormat( | ||
606 | "[BUNCH OF CAPS]: Created new inventory item '{0}' ({1}) for texture uploaded with mesh object {2}", | ||
607 | textureItem.Name, textureItem.ID, assetName); | ||
608 | } | ||
609 | } | ||
610 | 939 | ||
611 | if (clientInv != null && (foldersToUpdate.Count > 0 || itemsToUpdate.Count > 0)) | 940 | // skip prims that are 2 small |
612 | { | 941 | Vector3 scale = inner_instance_list["scale"].AsVector3(); |
613 | clientInv.SendBulkUpdateInventory(foldersToUpdate.ToArray(), itemsToUpdate.ToArray()); | ||
614 | } | ||
615 | 942 | ||
616 | for (int i = 0; i < mesh_list.Count; i++) | 943 | if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin) |
617 | { | 944 | { |
618 | PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); | 945 | skipedMeshs++; |
946 | continue; | ||
947 | } | ||
619 | 948 | ||
620 | Primitive.TextureEntry textureEntry | 949 | OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; |
621 | = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE); | ||
622 | OSDMap inner_instance_list = (OSDMap)instance_list[i]; | ||
623 | 950 | ||
624 | OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; | 951 | PrimitiveBaseShape pbs = null; |
625 | for (uint face = 0; face < face_list.Count; face++) | 952 | if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ... |
626 | { | 953 | { |
627 | OSDMap faceMap = (OSDMap)face_list[(int)face]; | 954 | int meshindx = inner_instance_list["mesh"].AsInteger(); |
628 | Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); | 955 | if (meshAssets.Count > meshindx) |
629 | if(faceMap.ContainsKey("fullbright")) | 956 | pbs = PrimitiveBaseShape.CreateMesh(face_list.Count, meshAssets[meshindx]); |
630 | f.Fullbright = faceMap["fullbright"].AsBoolean(); | 957 | } |
631 | if (faceMap.ContainsKey ("diffuse_color")) | 958 | if(pbs == null) // fallback |
632 | f.RGBA = faceMap["diffuse_color"].AsColor4(); | 959 | pbs = PrimitiveBaseShape.CreateBox(); |
960 | |||
961 | Primitive.TextureEntry textureEntry | ||
962 | = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE); | ||
963 | |||
964 | for (uint face = 0; face < face_list.Count; face++) | ||
965 | { | ||
966 | OSDMap faceMap = (OSDMap)face_list[(int)face]; | ||
633 | 967 | ||
634 | int textureNum = faceMap["image"].AsInteger(); | 968 | Primitive.TextureEntryFace f = textureEntry.CreateFace(face); //clone the default |
635 | float imagerot = faceMap["imagerot"].AsInteger(); | 969 | if (faceMap.ContainsKey("fullbright")) |
636 | float offsets = (float)faceMap["offsets"].AsReal(); | 970 | f.Fullbright = faceMap["fullbright"].AsBoolean(); |
637 | float offsett = (float)faceMap["offsett"].AsReal(); | 971 | if (faceMap.ContainsKey("diffuse_color")) |
638 | float scales = (float)faceMap["scales"].AsReal(); | 972 | f.RGBA = faceMap["diffuse_color"].AsColor4(); |
639 | float scalet = (float)faceMap["scalet"].AsReal(); | ||
640 | 973 | ||
641 | if(imagerot != 0) | 974 | int textureNum = faceMap["image"].AsInteger(); |
642 | f.Rotation = imagerot; | 975 | float imagerot = faceMap["imagerot"].AsInteger(); |
976 | float offsets = (float)faceMap["offsets"].AsReal(); | ||
977 | float offsett = (float)faceMap["offsett"].AsReal(); | ||
978 | float scales = (float)faceMap["scales"].AsReal(); | ||
979 | float scalet = (float)faceMap["scalet"].AsReal(); | ||
643 | 980 | ||
644 | if(offsets != 0) | 981 | if (imagerot != 0) |
645 | f.OffsetU = offsets; | 982 | f.Rotation = imagerot; |
646 | 983 | ||
647 | if (offsett != 0) | 984 | if (offsets != 0) |
648 | f.OffsetV = offsett; | 985 | f.OffsetU = offsets; |
649 | 986 | ||
650 | if (scales != 0) | 987 | if (offsett != 0) |
651 | f.RepeatU = scales; | 988 | f.OffsetV = offsett; |
652 | 989 | ||
653 | if (scalet != 0) | 990 | if (scales != 0) |
654 | f.RepeatV = scalet; | 991 | f.RepeatU = scales; |
655 | 992 | ||
656 | if (textures.Count > textureNum) | 993 | if (scalet != 0) |
657 | f.TextureID = textures[textureNum]; | 994 | f.RepeatV = scalet; |
995 | |||
996 | if (textures.Count > textureNum) | ||
997 | f.TextureID = textures[textureNum]; | ||
998 | |||
999 | textureEntry.FaceTextures[face] = f; | ||
1000 | } | ||
1001 | pbs.TextureEntry = textureEntry.GetBytes(); | ||
1002 | |||
1003 | Vector3 position = inner_instance_list["position"].AsVector3(); | ||
1004 | Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); | ||
1005 | |||
1006 | // for now viwers do send fixed defaults | ||
1007 | // but this may change | ||
1008 | // int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger(); | ||
1009 | byte physicsShapeType = (byte)PhysShapeType.convex; // default is simple convex | ||
1010 | // int material = inner_instance_list["material"].AsInteger(); | ||
1011 | byte material = (byte)Material.Wood; | ||
1012 | |||
1013 | SceneObjectPart prim | ||
1014 | = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); | ||
1015 | |||
1016 | prim.Scale = scale; | ||
1017 | rotations.Add(rotation); | ||
1018 | positions.Add(position); | ||
1019 | prim.UUID = UUID.Random(); | ||
1020 | prim.CreatorID = creatorID; | ||
1021 | prim.OwnerID = owner_id; | ||
1022 | prim.GroupID = UUID.Zero; | ||
1023 | prim.LastOwnerID = creatorID; | ||
1024 | prim.RezzerID = creatorID; | ||
1025 | prim.CreationDate = Util.UnixTimeSinceEpoch(); | ||
1026 | |||
1027 | if (grp == null) | ||
1028 | prim.Name = assetName; | ||
658 | else | 1029 | else |
659 | f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE; | 1030 | prim.Name = assetName + "#" + i.ToString(); |
660 | 1031 | ||
661 | textureEntry.FaceTextures[face] = f; | 1032 | prim.EveryoneMask = 0; |
662 | } | 1033 | prim.GroupMask = 0; |
663 | 1034 | ||
664 | pbs.TextureEntry = textureEntry.GetBytes(); | 1035 | if (restrictPerms) |
665 | 1036 | { | |
666 | AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); | 1037 | prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify); |
667 | meshAsset.Data = mesh_list[i].AsBinary(); | 1038 | prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify); |
668 | m_assetService.Store(meshAsset); | 1039 | prim.NextOwnerMask = 0; |
669 | 1040 | } | |
670 | pbs.SculptEntry = true; | 1041 | else |
671 | pbs.SculptTexture = meshAsset.FullID; | 1042 | { |
672 | pbs.SculptType = (byte)SculptType.Mesh; | 1043 | prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export; |
673 | pbs.SculptData = meshAsset.Data; | 1044 | prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export; |
674 | 1045 | prim.GroupMask = prim.BaseMask & (uint)groupMask; | |
675 | Vector3 position = inner_instance_list["position"].AsVector3(); | 1046 | prim.EveryoneMask = prim.BaseMask & (uint)everyoneMask; |
676 | Vector3 scale = inner_instance_list["scale"].AsVector3(); | 1047 | prim.NextOwnerMask = prim.BaseMask & (uint)nextOwnerMask; |
677 | Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); | 1048 | // If the viewer gives us bogus permissions, revert to the SL |
678 | 1049 | // default of transfer only. | |
679 | // no longer used - begin ------------------------ | 1050 | if ((prim.NextOwnerMask & (uint)PermissionMask.All) == 0) |
680 | // int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger(); | 1051 | prim.NextOwnerMask = (uint)PermissionMask.Transfer; |
681 | // int material = inner_instance_list["material"].AsInteger(); | 1052 | } |
682 | // int mesh = inner_instance_list["mesh"].AsInteger(); | 1053 | |
683 | 1054 | if(istest) | |
684 | // OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; | 1055 | prim.Description = "For testing only. Other uses are prohibited"; |
685 | // int base_mask = permissions["base_mask"].AsInteger(); | 1056 | else |
686 | // int everyone_mask = permissions["everyone_mask"].AsInteger(); | 1057 | prim.Description = ""; |
687 | // UUID creator_id = permissions["creator_id"].AsUUID(); | 1058 | |
688 | // UUID group_id = permissions["group_id"].AsUUID(); | 1059 | prim.Material = material; |
689 | // int group_mask = permissions["group_mask"].AsInteger(); | 1060 | prim.PhysicsShapeType = physicsShapeType; |
690 | // bool is_owner_group = permissions["is_owner_group"].AsBoolean(); | ||
691 | // UUID last_owner_id = permissions["last_owner_id"].AsUUID(); | ||
692 | // int next_owner_mask = permissions["next_owner_mask"].AsInteger(); | ||
693 | // UUID owner_id = permissions["owner_id"].AsUUID(); | ||
694 | // int owner_mask = permissions["owner_mask"].AsInteger(); | ||
695 | // no longer used - end ------------------------ | ||
696 | |||
697 | UUID owner_id = m_HostCapsObj.AgentID; | ||
698 | |||
699 | SceneObjectPart prim | ||
700 | = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); | ||
701 | |||
702 | prim.Scale = scale; | ||
703 | //prim.OffsetPosition = position; | ||
704 | rotations.Add(rotation); | ||
705 | positions.Add(position); | ||
706 | prim.UUID = UUID.Random(); | ||
707 | prim.CreatorID = owner_id; | ||
708 | prim.OwnerID = owner_id; | ||
709 | prim.GroupID = UUID.Zero; | ||
710 | prim.LastOwnerID = prim.OwnerID; | ||
711 | prim.CreationDate = Util.UnixTimeSinceEpoch(); | ||
712 | prim.Name = assetName; | ||
713 | prim.Description = ""; | ||
714 | 1061 | ||
715 | // prim.BaseMask = (uint)base_mask; | 1062 | // prim.BaseMask = (uint)base_mask; |
716 | // prim.EveryoneMask = (uint)everyone_mask; | 1063 | // prim.EveryoneMask = (uint)everyone_mask; |
@@ -718,52 +1065,65 @@ namespace OpenSim.Region.ClientStack.Linden | |||
718 | // prim.NextOwnerMask = (uint)next_owner_mask; | 1065 | // prim.NextOwnerMask = (uint)next_owner_mask; |
719 | // prim.OwnerMask = (uint)owner_mask; | 1066 | // prim.OwnerMask = (uint)owner_mask; |
720 | 1067 | ||
721 | if (grp == null) | 1068 | if (grp == null) |
722 | grp = new SceneObjectGroup(prim); | 1069 | { |
723 | else | 1070 | grp = new SceneObjectGroup(prim); |
724 | grp.AddPart(prim); | 1071 | grp.LastOwnerID = creatorID; |
725 | } | 1072 | grp.RezzerID = creatorID; |
1073 | } | ||
1074 | else | ||
1075 | grp.AddPart(prim); | ||
1076 | } | ||
726 | 1077 | ||
727 | Vector3 rootPos = positions[0]; | 1078 | Vector3 rootPos = positions[0]; |
728 | 1079 | ||
729 | if (grp.Parts.Length > 1) | 1080 | if (grp.Parts.Length > 1) |
730 | { | 1081 | { |
731 | // Fix first link number | 1082 | // Fix first link number |
732 | grp.RootPart.LinkNum++; | 1083 | grp.RootPart.LinkNum++; |
733 | 1084 | ||
734 | Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); | 1085 | Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); |
735 | Quaternion tmprot; | 1086 | Quaternion tmprot; |
736 | Vector3 offset; | 1087 | Vector3 offset; |
737 | 1088 | ||
738 | // fix children rotations and positions | 1089 | // fix children rotations and positions |
739 | for (int i = 1; i < rotations.Count; i++) | 1090 | for (int i = 1; i < rotations.Count; i++) |
740 | { | 1091 | { |
741 | tmprot = rotations[i]; | 1092 | tmprot = rotations[i]; |
742 | tmprot = rootRotConj * tmprot; | 1093 | tmprot = rootRotConj * tmprot; |
1094 | |||
1095 | grp.Parts[i].RotationOffset = tmprot; | ||
743 | 1096 | ||
744 | grp.Parts[i].RotationOffset = tmprot; | 1097 | offset = positions[i] - rootPos; |
745 | 1098 | ||
746 | offset = positions[i] - rootPos; | 1099 | offset *= rootRotConj; |
1100 | grp.Parts[i].OffsetPosition = offset; | ||
1101 | } | ||
747 | 1102 | ||
748 | offset *= rootRotConj; | 1103 | grp.AbsolutePosition = rootPos; |
749 | grp.Parts[i].OffsetPosition = offset; | 1104 | grp.UpdateGroupRotationR(rotations[0]); |
1105 | } | ||
1106 | else | ||
1107 | { | ||
1108 | grp.AbsolutePosition = rootPos; | ||
1109 | grp.UpdateGroupRotationR(rotations[0]); | ||
750 | } | 1110 | } |
751 | 1111 | ||
752 | grp.AbsolutePosition = rootPos; | 1112 | data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp)); |
753 | grp.UpdateGroupRotationR(rotations[0]); | ||
754 | } | 1113 | } |
755 | else | 1114 | |
1115 | else // not a mesh model | ||
756 | { | 1116 | { |
757 | grp.AbsolutePosition = rootPos; | 1117 | m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload"); |
758 | grp.UpdateGroupRotationR(rotations[0]); | 1118 | return; |
759 | } | 1119 | } |
760 | |||
761 | data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp)); | ||
762 | } | 1120 | } |
763 | 1121 | ||
764 | AssetBase asset; | 1122 | AssetBase asset; |
765 | asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); | 1123 | asset = new AssetBase(assetID, assetName, assType, creatorIDstr); |
766 | asset.Data = data; | 1124 | asset.Data = data; |
1125 | if (istest) | ||
1126 | asset.Local = true; | ||
767 | if (AddNewAsset != null) | 1127 | if (AddNewAsset != null) |
768 | AddNewAsset(asset); | 1128 | AddNewAsset(asset); |
769 | else if (m_assetService != null) | 1129 | else if (m_assetService != null) |
@@ -771,11 +1131,17 @@ namespace OpenSim.Region.ClientStack.Linden | |||
771 | 1131 | ||
772 | InventoryItemBase item = new InventoryItemBase(); | 1132 | InventoryItemBase item = new InventoryItemBase(); |
773 | item.Owner = m_HostCapsObj.AgentID; | 1133 | item.Owner = m_HostCapsObj.AgentID; |
774 | item.CreatorId = m_HostCapsObj.AgentID.ToString(); | 1134 | item.CreatorId = creatorIDstr; |
775 | item.CreatorData = String.Empty; | 1135 | item.CreatorData = String.Empty; |
776 | item.ID = inventoryItem; | 1136 | item.ID = inventoryItem; |
777 | item.AssetID = asset.FullID; | 1137 | item.AssetID = asset.FullID; |
778 | item.Description = assetDescription; | 1138 | if (istest) |
1139 | { | ||
1140 | item.Description = "For testing only. Other uses are prohibited"; | ||
1141 | item.Flags = (uint) (InventoryItemFlags.SharedSingleReference); | ||
1142 | } | ||
1143 | else | ||
1144 | item.Description = assetDescription; | ||
779 | item.Name = assetName; | 1145 | item.Name = assetName; |
780 | item.AssetType = assType; | 1146 | item.AssetType = assType; |
781 | item.InvType = inType; | 1147 | item.InvType = inType; |
@@ -783,18 +1149,69 @@ namespace OpenSim.Region.ClientStack.Linden | |||
783 | 1149 | ||
784 | // If we set PermissionMask.All then when we rez the item the next permissions will replace the current | 1150 | // If we set PermissionMask.All then when we rez the item the next permissions will replace the current |
785 | // (owner) permissions. This becomes a problem if next permissions are changed. | 1151 | // (owner) permissions. This becomes a problem if next permissions are changed. |
786 | item.CurrentPermissions | ||
787 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export); | ||
788 | 1152 | ||
789 | item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; | 1153 | if (inType == (sbyte)CustomInventoryType.AnimationSet) |
790 | item.EveryOnePermissions = 0; | 1154 | { |
791 | item.NextPermissions = (uint)PermissionMask.All; | 1155 | AnimationSet.setCreateItemPermitions(item); |
1156 | } | ||
1157 | |||
1158 | else if (restrictPerms) | ||
1159 | { | ||
1160 | item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify); | ||
1161 | item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify); | ||
1162 | item.GroupPermissions = 0; | ||
1163 | item.EveryOnePermissions = 0; | ||
1164 | item.NextPermissions = 0; | ||
1165 | } | ||
1166 | else | ||
1167 | { | ||
1168 | item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; | ||
1169 | item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; | ||
1170 | item.GroupPermissions = item.BasePermissions & (uint)groupMask; | ||
1171 | item.EveryOnePermissions = item.BasePermissions & (uint)everyoneMask; | ||
1172 | item.NextPermissions = item.BasePermissions & (uint)nextOwnerMask; | ||
1173 | if ((item.NextPermissions & (uint)PermissionMask.All) == 0) | ||
1174 | item.NextPermissions = (uint)PermissionMask.Transfer; | ||
1175 | } | ||
1176 | |||
792 | item.CreationDate = Util.UnixTimeSinceEpoch(); | 1177 | item.CreationDate = Util.UnixTimeSinceEpoch(); |
793 | 1178 | ||
1179 | everyoneMask = (int)item.EveryOnePermissions; | ||
1180 | groupMask = (int)item.GroupPermissions; | ||
1181 | nextOwnerMask = (int)item.NextPermissions; | ||
1182 | |||
1183 | m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); | ||
1184 | |||
794 | if (AddNewInventoryItem != null) | 1185 | if (AddNewInventoryItem != null) |
795 | { | 1186 | { |
796 | AddNewInventoryItem(m_HostCapsObj.AgentID, item); | 1187 | if (istest) |
1188 | { | ||
1189 | m_Scene.AddInventoryItem(client, item); | ||
1190 | /* | ||
1191 | AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0); | ||
1192 | if (client != null) | ||
1193 | client.SendAgentAlertMessage("Upload will have no cost, for personal test purposes only. Other uses are forbiden. Items may not work on a another region" , true); | ||
1194 | */ | ||
1195 | } | ||
1196 | else | ||
1197 | { | ||
1198 | AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost); | ||
1199 | // if (client != null) | ||
1200 | // { | ||
1201 | // // let users see anything.. i don't so far | ||
1202 | // string str; | ||
1203 | // if (cost > 0) | ||
1204 | // // dont remember where is money unit name to put here | ||
1205 | // str = "Upload complete. charged " + cost.ToString() + "$"; | ||
1206 | // else | ||
1207 | // str = "Upload complete"; | ||
1208 | // client.SendAgentAlertMessage(str, true); | ||
1209 | // } | ||
1210 | } | ||
797 | } | 1211 | } |
1212 | |||
1213 | lock (m_ModelCost) | ||
1214 | m_FileAgentInventoryState = FileAgentInventoryState.idle; | ||
798 | } | 1215 | } |
799 | 1216 | ||
800 | /// <summary> | 1217 | /// <summary> |
@@ -857,24 +1274,22 @@ namespace OpenSim.Region.ClientStack.Linden | |||
857 | LLSDItemUpdate llsdRequest = new LLSDItemUpdate(); | 1274 | LLSDItemUpdate llsdRequest = new LLSDItemUpdate(); |
858 | LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); | 1275 | LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); |
859 | 1276 | ||
860 | string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | 1277 | string uploaderPath = GetNewCapPath(); |
861 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||
862 | 1278 | ||
863 | ItemUpdater uploader = | 1279 | ItemUpdater uploader = |
864 | new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); | 1280 | new ItemUpdater(llsdRequest.item_id, uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); |
865 | uploader.OnUpLoad += ItemUpdated; | 1281 | uploader.OnUpLoad += ItemUpdated; |
866 | 1282 | ||
867 | m_HostCapsObj.HttpListener.AddStreamHandler( | 1283 | m_HostCapsObj.HttpListener.AddStreamHandler( |
868 | new BinaryStreamHandler( | 1284 | new BinaryStreamHandler( |
869 | "POST", capsBase + uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null)); | 1285 | "POST", uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null)); |
870 | 1286 | ||
871 | string protocol = "http://"; | 1287 | string protocol = "http://"; |
872 | 1288 | ||
873 | if (m_HostCapsObj.SSLCaps) | 1289 | if (m_HostCapsObj.SSLCaps) |
874 | protocol = "https://"; | 1290 | protocol = "https://"; |
875 | 1291 | ||
876 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + | 1292 | string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath; |
877 | uploaderPath; | ||
878 | 1293 | ||
879 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | 1294 | LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); |
880 | uploadResponse.uploader = uploaderURL; | 1295 | uploadResponse.uploader = uploaderURL; |
@@ -930,29 +1345,22 @@ namespace OpenSim.Region.ClientStack.Linden | |||
930 | IClientAPI client = null; | 1345 | IClientAPI client = null; |
931 | 1346 | ||
932 | m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); | 1347 | m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); |
933 | item = m_Scene.InventoryService.GetItem(new InventoryItemBase(itemID)); | 1348 | item = m_Scene.InventoryService.GetItem(m_HostCapsObj.AgentID, itemID); |
934 | if (item != null) | 1349 | if (item != null) |
935 | { | 1350 | { |
936 | string message; | 1351 | string message; |
937 | copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID, out message); | 1352 | copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID, out message); |
938 | if (client != null) | 1353 | if (copyItem != null && client != null) |
939 | { | 1354 | { |
940 | if (copyItem != null) | 1355 | m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder); |
941 | { | 1356 | client.SendBulkUpdateInventory(copyItem); |
942 | m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder); | ||
943 | client.SendBulkUpdateInventory(copyItem); | ||
944 | } | ||
945 | else | ||
946 | { | ||
947 | client.SendAgentAlertMessage(message, false); | ||
948 | } | ||
949 | } | 1357 | } |
950 | } | 1358 | } |
951 | else | 1359 | else |
952 | { | 1360 | { |
953 | m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID); | 1361 | m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID); |
954 | if (client != null) | 1362 | if (client != null) |
955 | client.SendAgentAlertMessage("Failed to retrieve item", false); | 1363 | client.SendAlertMessage("Failed to retrieve item"); |
956 | } | 1364 | } |
957 | } | 1365 | } |
958 | catch (Exception e) | 1366 | catch (Exception e) |
@@ -995,26 +1403,483 @@ namespace OpenSim.Region.ClientStack.Linden | |||
995 | return response; | 1403 | return response; |
996 | } | 1404 | } |
997 | 1405 | ||
998 | public string UpdateAgentInformation(string request, string path, | 1406 | public string GetObjectCost(string request, string path, |
999 | string param, IOSHttpRequest httpRequest, | 1407 | string param, IOSHttpRequest httpRequest, |
1000 | IOSHttpResponse httpResponse) | 1408 | IOSHttpResponse httpResponse) |
1001 | { | 1409 | { |
1002 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | 1410 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); |
1003 | OSDMap accessPrefs = (OSDMap)req["access_prefs"]; | 1411 | OSDMap resp = new OSDMap(); |
1004 | string desiredMaturity = accessPrefs["max"]; | 1412 | |
1413 | OSDArray object_ids = (OSDArray)req["object_ids"]; | ||
1414 | |||
1415 | for (int i = 0; i < object_ids.Count; i++) | ||
1416 | { | ||
1417 | UUID uuid = object_ids[i].AsUUID(); | ||
1005 | 1418 | ||
1419 | SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid); | ||
1420 | SceneObjectGroup grp = null; | ||
1421 | if (part != null) | ||
1422 | grp = part.ParentGroup; | ||
1423 | if (grp != null) | ||
1424 | { | ||
1425 | float linksetCost; | ||
1426 | float linksetPhysCost; | ||
1427 | float partCost; | ||
1428 | float partPhysCost; | ||
1429 | |||
1430 | grp.GetResourcesCosts(part,out linksetCost,out linksetPhysCost,out partCost,out partPhysCost); | ||
1431 | |||
1432 | OSDMap object_data = new OSDMap(); | ||
1433 | object_data["linked_set_resource_cost"] = linksetCost; | ||
1434 | object_data["resource_cost"] = partCost; | ||
1435 | object_data["physics_cost"] = partPhysCost; | ||
1436 | object_data["linked_set_physics_cost"] = linksetPhysCost; | ||
1437 | object_data["resource_limiting_type"] = "legacy"; | ||
1438 | resp[uuid.ToString()] = object_data; | ||
1439 | } | ||
1440 | } | ||
1441 | if(resp.Count == 0) | ||
1442 | { | ||
1443 | OSDMap object_data = new OSDMap(); | ||
1444 | object_data["linked_set_resource_cost"] = 0; | ||
1445 | object_data["resource_cost"] = 0; | ||
1446 | object_data["physics_cost"] = 0; | ||
1447 | object_data["linked_set_physics_cost"] = 0; | ||
1448 | resp[UUID.Zero.ToString()] = object_data; | ||
1449 | } | ||
1450 | string response = OSDParser.SerializeLLSDXmlString(resp); | ||
1451 | return response; | ||
1452 | } | ||
1453 | |||
1454 | public string ResourceCostSelected(string request, string path, | ||
1455 | string param, IOSHttpRequest httpRequest, | ||
1456 | IOSHttpResponse httpResponse) | ||
1457 | { | ||
1458 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
1006 | OSDMap resp = new OSDMap(); | 1459 | OSDMap resp = new OSDMap(); |
1007 | OSDMap respAccessPrefs = new OSDMap(); | ||
1008 | respAccessPrefs["max"] = desiredMaturity; // echoing the maturity back means success | ||
1009 | resp["access_prefs"] = respAccessPrefs; | ||
1010 | 1460 | ||
1461 | |||
1462 | float phys=0; | ||
1463 | float stream=0; | ||
1464 | float simul=0; | ||
1465 | |||
1466 | if (req.ContainsKey("selected_roots")) | ||
1467 | { | ||
1468 | OSDArray object_ids = (OSDArray)req["selected_roots"]; | ||
1469 | |||
1470 | // should go by SOG suming costs for all parts | ||
1471 | // ll v3 works ok with several objects select we get the list and adds ok | ||
1472 | // FS calls per object so results are wrong guess fs bug | ||
1473 | for (int i = 0; i < object_ids.Count; i++) | ||
1474 | { | ||
1475 | UUID uuid = object_ids[i].AsUUID(); | ||
1476 | float Physc; | ||
1477 | float simulc; | ||
1478 | float streamc; | ||
1479 | |||
1480 | SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid); | ||
1481 | if (grp != null) | ||
1482 | { | ||
1483 | grp.GetSelectedCosts(out Physc, out streamc, out simulc); | ||
1484 | phys += Physc; | ||
1485 | stream += streamc; | ||
1486 | simul += simulc; | ||
1487 | } | ||
1488 | } | ||
1489 | } | ||
1490 | else if (req.ContainsKey("selected_prims")) | ||
1491 | { | ||
1492 | OSDArray object_ids = (OSDArray)req["selected_prims"]; | ||
1493 | |||
1494 | // don't see in use in any of the 2 viewers | ||
1495 | // guess it should be for edit linked but... nothing | ||
1496 | // should go to SOP per part | ||
1497 | for (int i = 0; i < object_ids.Count; i++) | ||
1498 | { | ||
1499 | UUID uuid = object_ids[i].AsUUID(); | ||
1500 | |||
1501 | SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid); | ||
1502 | if (part != null) | ||
1503 | { | ||
1504 | phys += part.PhysicsCost; | ||
1505 | stream += part.StreamingCost; | ||
1506 | simul += part.SimulationCost; | ||
1507 | } | ||
1508 | } | ||
1509 | } | ||
1510 | |||
1511 | OSDMap object_data = new OSDMap(); | ||
1512 | |||
1513 | object_data["physics"] = phys; | ||
1514 | object_data["streaming"] = stream; | ||
1515 | object_data["simulation"] = simul; | ||
1516 | |||
1517 | resp["selected"] = object_data; | ||
1518 | // resp["transaction_id"] = "undef"; | ||
1011 | string response = OSDParser.SerializeLLSDXmlString(resp); | 1519 | string response = OSDParser.SerializeLLSDXmlString(resp); |
1012 | return response; | 1520 | return response; |
1521 | } | ||
1522 | |||
1523 | public string UpdateAgentInformation(string request, string path, | ||
1524 | string param, IOSHttpRequest httpRequest, | ||
1525 | IOSHttpResponse httpResponse) | ||
1526 | { | ||
1527 | // OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
1528 | OSDMap resp = new OSDMap(); | ||
1529 | |||
1530 | OSDMap accessPrefs = new OSDMap(); | ||
1531 | accessPrefs["max"] = "A"; | ||
1532 | |||
1533 | resp["access_prefs"] = accessPrefs; | ||
1534 | |||
1535 | string response = OSDParser.SerializeLLSDXmlString(resp); | ||
1536 | return response; | ||
1537 | } | ||
1538 | |||
1539 | public bool OSDMapTOVector3(OSDMap map, out Vector3 v) | ||
1540 | { | ||
1541 | v = Vector3.Zero; | ||
1542 | if(!map.ContainsKey("X")) | ||
1543 | return false; | ||
1544 | if(!map.ContainsKey("Y")) | ||
1545 | return false; | ||
1546 | if(!map.ContainsKey("Z")) | ||
1547 | return false; | ||
1548 | v.X = (float)map["X"].AsReal(); | ||
1549 | v.Y = (float)map["Y"].AsReal(); | ||
1550 | v.Z = (float)map["Z"].AsReal(); | ||
1551 | return true; | ||
1552 | } | ||
1553 | |||
1554 | public string HomeLocation(string request, string path, string param, IOSHttpRequest httpRequest, | ||
1555 | IOSHttpResponse httpResponse) | ||
1556 | { | ||
1557 | OSDMap resp = new OSDMap(); | ||
1558 | |||
1559 | resp["success"] = "false"; | ||
1560 | |||
1561 | |||
1562 | bool fail = true; | ||
1563 | string message = "Set Home request failed"; | ||
1564 | int locationID = 1; | ||
1565 | Vector3 pos = Vector3.Zero; | ||
1566 | Vector3 lookAt = Vector3.Zero; | ||
1567 | |||
1568 | IClientAPI client = null; | ||
1569 | ScenePresence sp; | ||
1570 | |||
1571 | while(true) | ||
1572 | { | ||
1573 | if(m_Scene.GridUserService == null) | ||
1574 | break; | ||
1575 | |||
1576 | if(m_Scene.UserManagementModule == null) | ||
1577 | break; | ||
1578 | |||
1579 | m_Scene.TryGetScenePresence(m_AgentID, out sp); | ||
1580 | if(sp == null || sp.IsChildAgent || sp.IsDeleted) | ||
1581 | break; | ||
1582 | |||
1583 | if(sp.IsInTransit && !sp.IsInLocalTransit) | ||
1584 | break; | ||
1585 | |||
1586 | client = sp.ControllingClient; | ||
1587 | |||
1588 | if(!m_Scene.UserManagementModule.IsLocalGridUser(m_AgentID)) | ||
1589 | break; | ||
1590 | |||
1591 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
1592 | if(!req.ContainsKey("HomeLocation")) | ||
1593 | break; | ||
1594 | |||
1595 | OSDMap HLocation = (OSDMap)req["HomeLocation"]; | ||
1596 | if(!HLocation.ContainsKey("LocationPos")) | ||
1597 | break; | ||
1598 | if(!HLocation.ContainsKey("LocationLookAt")) | ||
1599 | break; | ||
1600 | |||
1601 | locationID = HLocation["LocationId"].AsInteger(); | ||
1602 | |||
1603 | if(!OSDMapTOVector3((OSDMap)HLocation["LocationPos"], out pos)) | ||
1604 | break; | ||
1605 | |||
1606 | if(!OSDMapTOVector3((OSDMap)HLocation["LocationLookAt"], out lookAt)) | ||
1607 | break; | ||
1608 | |||
1609 | ILandObject land = m_Scene.LandChannel.GetLandObject(pos); | ||
1610 | if(land == null) | ||
1611 | break; | ||
1612 | |||
1613 | ulong gpowers = client.GetGroupPowers(land.LandData.GroupID); | ||
1614 | SceneObjectGroup telehub = null; | ||
1615 | if (m_Scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero) | ||
1616 | // Does the telehub exist in the scene? | ||
1617 | telehub = m_Scene.GetSceneObjectGroup(m_Scene.RegionInfo.RegionSettings.TelehubObject); | ||
1618 | |||
1619 | if (!m_Scene.Permissions.IsAdministrator(m_AgentID) && // (a) gods and land managers can set home | ||
1620 | !m_Scene.Permissions.IsGod(m_AgentID) && | ||
1621 | m_AgentID != land.LandData.OwnerID && // (b) land owners can set home | ||
1622 | // (c) members of the land-associated group in roles that can set home | ||
1623 | ((gpowers & (ulong)GroupPowers.AllowSetHome) != (ulong)GroupPowers.AllowSetHome) && | ||
1624 | // (d) parcels with telehubs can be the home of anyone | ||
1625 | (telehub == null || !land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y))) | ||
1626 | { | ||
1627 | message = "You are not allowed to set your home location in this parcel."; | ||
1628 | break; | ||
1629 | } | ||
1630 | |||
1631 | string userId; | ||
1632 | UUID test; | ||
1633 | if (!m_Scene.UserManagementModule.GetUserUUI(m_AgentID, out userId)) | ||
1634 | { | ||
1635 | message = "Set Home request failed. (User Lookup)"; | ||
1636 | break; | ||
1637 | } | ||
1638 | |||
1639 | if (!UUID.TryParse(userId, out test)) | ||
1640 | { | ||
1641 | message = "Set Home request failed. (HG visitor)"; | ||
1642 | break; | ||
1643 | } | ||
1644 | |||
1645 | if (m_Scene.GridUserService.SetHome(userId, land.RegionUUID, pos, lookAt)) | ||
1646 | fail = false; | ||
1647 | |||
1648 | break; | ||
1649 | } | ||
1650 | |||
1651 | string response; | ||
1652 | |||
1653 | if(fail) | ||
1654 | { | ||
1655 | if(client != null) | ||
1656 | client.SendAlertMessage(message); | ||
1657 | response = OSDParser.SerializeLLSDXmlString(resp); | ||
1658 | return response; | ||
1659 | } | ||
1660 | |||
1661 | // so its http but still needs a udp reply to inform user? crap :p | ||
1662 | if(client != null) | ||
1663 | client.SendAlertMessage("Home position set.","HomePositionSet"); | ||
1664 | |||
1665 | resp["success"] = "true"; | ||
1666 | OSDMap homeloc = new OSDMap(); | ||
1667 | OSDMap homelocpos = new OSDMap(); | ||
1668 | // for some odd reason viewers send pos as reals but read as integer | ||
1669 | homelocpos["X"] = new OSDReal(pos.X); | ||
1670 | homelocpos["Y"] = new OSDReal(pos.Y); | ||
1671 | homelocpos["Z"] = new OSDReal(pos.Z); | ||
1672 | homeloc["LocationPos"] = homelocpos; | ||
1673 | |||
1674 | resp["HomeLocation"] = homeloc; | ||
1675 | |||
1676 | response = OSDParser.SerializeLLSDXmlString(resp); | ||
1677 | return response; | ||
1678 | } | ||
1679 | |||
1680 | private static int CompareRolesByMembersDesc(GroupRolesData x, GroupRolesData y) | ||
1681 | { | ||
1682 | return -(x.Members.CompareTo(y.Members)); | ||
1683 | } | ||
1684 | |||
1685 | public string GroupMemberData(string request, string path, string param, IOSHttpRequest httpRequest, | ||
1686 | IOSHttpResponse httpResponse) | ||
1687 | { | ||
1688 | OSDMap resp = new OSDMap(); | ||
1689 | |||
1690 | string response; | ||
1691 | |||
1692 | bool fail = true; | ||
1693 | IClientAPI client = null; | ||
1694 | ScenePresence sp; | ||
1695 | IGroupsModule m_GroupsModule; | ||
1696 | UUID groupID = UUID.Zero; | ||
1697 | |||
1698 | while(true) | ||
1699 | { | ||
1700 | m_GroupsModule = m_Scene.RequestModuleInterface<IGroupsModule>(); | ||
1701 | if(m_GroupsModule == null) | ||
1702 | break; | ||
1703 | |||
1704 | m_Scene.TryGetScenePresence(m_AgentID, out sp); | ||
1705 | if(sp == null || sp.IsChildAgent || sp.IsDeleted) | ||
1706 | break; | ||
1707 | |||
1708 | if(sp.IsInTransit && !sp.IsInLocalTransit) | ||
1709 | break; | ||
1710 | |||
1711 | client = sp.ControllingClient; | ||
1712 | |||
1713 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
1714 | if(!req.ContainsKey("group_id")) | ||
1715 | break; | ||
1716 | |||
1717 | groupID = req["group_id"].AsUUID(); | ||
1718 | if(groupID == UUID.Zero) | ||
1719 | break; | ||
1720 | |||
1721 | List<GroupRolesData> roles = m_GroupsModule.GroupRoleDataRequest(client, groupID); | ||
1722 | if(roles == null || roles.Count == 0) | ||
1723 | break; | ||
1724 | |||
1725 | List<GroupMembersData> members = m_GroupsModule.GroupMembersRequest(client, groupID); | ||
1726 | if(members == null || members.Count == 0) | ||
1727 | break; | ||
1728 | |||
1729 | int memberCount = members.Count; | ||
1730 | |||
1731 | Dictionary<string,int> titles = new Dictionary<string,int>(); | ||
1732 | int i = 0; | ||
1733 | |||
1734 | ulong defaultPowers = 0; | ||
1735 | |||
1736 | |||
1737 | // build titles array and index | ||
1738 | roles.Sort(CompareRolesByMembersDesc); | ||
1739 | |||
1740 | OSDArray osdtitles = new OSDArray(); | ||
1741 | foreach(GroupRolesData grd in roles) | ||
1742 | { | ||
1743 | if(grd.Title == null) | ||
1744 | continue; | ||
1745 | string title = grd.Title; | ||
1746 | if(i==0) | ||
1747 | defaultPowers = grd.Powers; | ||
1748 | |||
1749 | if(!titles.ContainsKey(title)) | ||
1750 | { | ||
1751 | titles[title] = i++; | ||
1752 | osdtitles.Add(new OSDString(title)); | ||
1753 | } | ||
1754 | } | ||
1755 | |||
1756 | if(titles.Count == 0) | ||
1757 | break; | ||
1758 | |||
1759 | OSDMap osdmembers = new OSDMap(); | ||
1760 | foreach(GroupMembersData gmd in members) | ||
1761 | { | ||
1762 | OSDMap m = new OSDMap(); | ||
1763 | if(gmd.OnlineStatus != null && gmd.OnlineStatus != "") | ||
1764 | m["last_login"] = new OSDString(gmd.OnlineStatus); | ||
1765 | if(gmd.AgentPowers != defaultPowers) | ||
1766 | m["powers"] = new OSDString((gmd.AgentPowers).ToString("X")); | ||
1767 | if(gmd.Title != null && titles.ContainsKey(gmd.Title) && titles[gmd.Title] != 0) | ||
1768 | m["title"] = new OSDInteger(titles[gmd.Title]); | ||
1769 | if(gmd.IsOwner) | ||
1770 | m["owner"] = new OSDString("true"); | ||
1771 | if(gmd.Contribution != 0) | ||
1772 | m["donated_square_meters"] = new OSDInteger(gmd.Contribution); | ||
1773 | |||
1774 | osdmembers[(gmd.AgentID).ToString()] = m; | ||
1775 | } | ||
1776 | |||
1777 | OSDMap osddefaults = new OSDMap(); | ||
1778 | osddefaults["default_powers"] = new OSDString(defaultPowers.ToString("X")); | ||
1779 | |||
1780 | resp["group_id"] = new OSDUUID(groupID); | ||
1781 | resp["agent_id"] = new OSDUUID(m_AgentID); | ||
1782 | resp["member_count"] = new OSDInteger(memberCount); | ||
1783 | resp["defaults"] = osddefaults; | ||
1784 | resp["titles"] = osdtitles; | ||
1785 | resp["members"] = osdmembers; | ||
1786 | |||
1787 | fail = false; | ||
1788 | break; | ||
1789 | } | ||
1790 | |||
1791 | if(fail) | ||
1792 | { | ||
1793 | resp["group_id"] = new OSDUUID(groupID); | ||
1794 | resp["agent_id"] = new OSDUUID(m_AgentID); | ||
1795 | resp["member_count"] = new OSDInteger(0); | ||
1796 | resp["defaults"] = new OSDMap(); | ||
1797 | resp["titles"] = new OSDArray(); | ||
1798 | resp["members"] = new OSDMap(); | ||
1799 | } | ||
1800 | |||
1801 | response = OSDParser.SerializeLLSDXmlString(resp); | ||
1802 | return response; | ||
1803 | } | ||
1804 | |||
1805 | public string GetDisplayNames(string request, string path, | ||
1806 | string param, IOSHttpRequest httpRequest, | ||
1807 | IOSHttpResponse httpResponse) | ||
1808 | { | ||
1809 | httpResponse.StatusCode = (int)System.Net.HttpStatusCode.Gone; | ||
1810 | httpResponse.ContentType = "text/plain"; | ||
1811 | |||
1812 | ScenePresence sp = m_Scene.GetScenePresence(m_AgentID); | ||
1813 | if(sp == null || sp.IsDeleted) | ||
1814 | return ""; | ||
1815 | |||
1816 | if(sp.IsInTransit && !sp.IsInLocalTransit) | ||
1817 | { | ||
1818 | httpResponse.StatusCode = (int)System.Net.HttpStatusCode.ServiceUnavailable; | ||
1819 | httpResponse.AddHeader("Retry-After","30"); | ||
1820 | return ""; | ||
1821 | } | ||
1822 | |||
1823 | NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); | ||
1824 | string[] ids = query.GetValues("ids"); | ||
1825 | |||
1826 | Dictionary<UUID,string> names = m_UserManager.GetUsersNames(ids); | ||
1827 | |||
1828 | OSDMap osdReply = new OSDMap(); | ||
1829 | OSDArray agents = new OSDArray(); | ||
1830 | |||
1831 | osdReply["agents"] = agents; | ||
1832 | foreach (KeyValuePair<UUID,string> kvp in names) | ||
1833 | { | ||
1834 | if (string.IsNullOrEmpty(kvp.Value)) | ||
1835 | continue; | ||
1836 | if(kvp.Key == UUID.Zero) | ||
1837 | continue; | ||
1838 | |||
1839 | string[] parts = kvp.Value.Split(new char[] {' '}); | ||
1840 | OSDMap osdname = new OSDMap(); | ||
1841 | |||
1842 | // dont tell about unknown users, we can't send them back on Bad either | ||
1843 | if(parts[0] == "Unknown") | ||
1844 | continue; | ||
1845 | /* | ||
1846 | if(parts[0] == "Unknown") | ||
1847 | { | ||
1848 | osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddHours(1)); | ||
1849 | osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddHours(2)); | ||
1850 | } | ||
1851 | else | ||
1852 | */ | ||
1853 | { | ||
1854 | osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddDays(8)); | ||
1855 | osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddMonths(1)); | ||
1856 | } | ||
1857 | osdname["display_name"] = OSD.FromString(kvp.Value); | ||
1858 | osdname["legacy_first_name"] = parts[0]; | ||
1859 | osdname["legacy_last_name"] = parts[1]; | ||
1860 | osdname["username"] = OSD.FromString(kvp.Value); | ||
1861 | osdname["id"] = OSD.FromUUID(kvp.Key); | ||
1862 | osdname["is_display_name_default"] = OSD.FromBoolean(true); | ||
1863 | |||
1864 | agents.Add(osdname); | ||
1865 | } | ||
1866 | |||
1867 | // Full content request | ||
1868 | httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; | ||
1869 | //httpResponse.ContentLength = ??; | ||
1870 | httpResponse.ContentType = "application/llsd+xml"; | ||
1871 | |||
1872 | string reply = OSDParser.SerializeLLSDXmlString(osdReply); | ||
1873 | return reply; | ||
1013 | } | 1874 | } |
1014 | } | 1875 | } |
1015 | 1876 | ||
1016 | public class AssetUploader | 1877 | public class AssetUploader |
1017 | { | 1878 | { |
1879 | private static readonly ILog m_log = | ||
1880 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
1881 | |||
1882 | |||
1018 | public event UpLoadedAsset OnUpLoad; | 1883 | public event UpLoadedAsset OnUpLoad; |
1019 | private UpLoadedAsset handlerUpLoad = null; | 1884 | private UpLoadedAsset handlerUpLoad = null; |
1020 | 1885 | ||
@@ -1029,10 +1894,26 @@ namespace OpenSim.Region.ClientStack.Linden | |||
1029 | 1894 | ||
1030 | private string m_invType = String.Empty; | 1895 | private string m_invType = String.Empty; |
1031 | private string m_assetType = String.Empty; | 1896 | private string m_assetType = String.Empty; |
1897 | private int m_cost; | ||
1898 | private string m_error = String.Empty; | ||
1899 | |||
1900 | private Timer m_timeoutTimer = new Timer(); | ||
1901 | private UUID m_texturesFolder; | ||
1902 | private int m_nreqtextures; | ||
1903 | private int m_nreqmeshs; | ||
1904 | private int m_nreqinstances; | ||
1905 | private bool m_IsAtestUpload; | ||
1906 | |||
1907 | private int m_nextOwnerMask; | ||
1908 | private int m_groupMask; | ||
1909 | private int m_everyoneMask; | ||
1910 | |||
1032 | 1911 | ||
1033 | public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, | 1912 | public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, |
1034 | UUID parentFolderID, string invType, string assetType, string path, | 1913 | UUID parentFolderID, string invType, string assetType, string path, |
1035 | IHttpServer httpServer, bool dumpAssetsToFile) | 1914 | IHttpServer httpServer, bool dumpAssetsToFile, |
1915 | int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances, | ||
1916 | bool IsAtestUpload, int nextOwnerMask, int groupMask, int everyoneMask) | ||
1036 | { | 1917 | { |
1037 | m_assetName = assetName; | 1918 | m_assetName = assetName; |
1038 | m_assetDes = description; | 1919 | m_assetDes = description; |
@@ -1044,6 +1925,22 @@ namespace OpenSim.Region.ClientStack.Linden | |||
1044 | m_assetType = assetType; | 1925 | m_assetType = assetType; |
1045 | m_invType = invType; | 1926 | m_invType = invType; |
1046 | m_dumpAssetsToFile = dumpAssetsToFile; | 1927 | m_dumpAssetsToFile = dumpAssetsToFile; |
1928 | m_cost = totalCost; | ||
1929 | |||
1930 | m_texturesFolder = texturesFolder; | ||
1931 | m_nreqtextures = nreqtextures; | ||
1932 | m_nreqmeshs = nreqmeshs; | ||
1933 | m_nreqinstances = nreqinstances; | ||
1934 | m_IsAtestUpload = IsAtestUpload; | ||
1935 | |||
1936 | m_timeoutTimer.Elapsed += TimedOut; | ||
1937 | m_timeoutTimer.Interval = 120000; | ||
1938 | m_timeoutTimer.AutoReset = false; | ||
1939 | m_timeoutTimer.Start(); | ||
1940 | |||
1941 | m_nextOwnerMask = nextOwnerMask; | ||
1942 | m_groupMask = groupMask; | ||
1943 | m_everyoneMask = everyoneMask; | ||
1047 | } | 1944 | } |
1048 | 1945 | ||
1049 | /// <summary> | 1946 | /// <summary> |
@@ -1058,12 +1955,14 @@ namespace OpenSim.Region.ClientStack.Linden | |||
1058 | UUID inv = inventoryItemID; | 1955 | UUID inv = inventoryItemID; |
1059 | string res = String.Empty; | 1956 | string res = String.Empty; |
1060 | LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); | 1957 | LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); |
1958 | /* | ||
1061 | uploadComplete.new_asset = newAssetID.ToString(); | 1959 | uploadComplete.new_asset = newAssetID.ToString(); |
1062 | uploadComplete.new_inventory_item = inv; | 1960 | uploadComplete.new_inventory_item = inv; |
1063 | uploadComplete.state = "complete"; | 1961 | uploadComplete.state = "complete"; |
1064 | 1962 | ||
1065 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | 1963 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); |
1066 | 1964 | */ | |
1965 | m_timeoutTimer.Stop(); | ||
1067 | httpListener.RemoveStreamHandler("POST", uploaderPath); | 1966 | httpListener.RemoveStreamHandler("POST", uploaderPath); |
1068 | 1967 | ||
1069 | // TODO: probably make this a better set of extensions here | 1968 | // TODO: probably make this a better set of extensions here |
@@ -1080,12 +1979,55 @@ namespace OpenSim.Region.ClientStack.Linden | |||
1080 | handlerUpLoad = OnUpLoad; | 1979 | handlerUpLoad = OnUpLoad; |
1081 | if (handlerUpLoad != null) | 1980 | if (handlerUpLoad != null) |
1082 | { | 1981 | { |
1083 | handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); | 1982 | handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType, |
1983 | m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, | ||
1984 | ref m_error, ref m_nextOwnerMask, ref m_groupMask, ref m_everyoneMask); | ||
1084 | } | 1985 | } |
1085 | 1986 | ||
1987 | uploadComplete.new_next_owner_mask = m_nextOwnerMask; | ||
1988 | uploadComplete.new_group_mask = m_groupMask; | ||
1989 | uploadComplete.new_everyone_mask = m_everyoneMask; | ||
1990 | |||
1991 | if (m_IsAtestUpload) | ||
1992 | { | ||
1993 | LLSDAssetUploadError resperror = new LLSDAssetUploadError(); | ||
1994 | resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions"; | ||
1995 | resperror.identifier = inv; | ||
1996 | |||
1997 | uploadComplete.error = resperror; | ||
1998 | uploadComplete.state = "Upload4Testing"; | ||
1999 | } | ||
2000 | else | ||
2001 | { | ||
2002 | if (m_error == String.Empty) | ||
2003 | { | ||
2004 | uploadComplete.new_asset = newAssetID.ToString(); | ||
2005 | uploadComplete.new_inventory_item = inv; | ||
2006 | // if (m_texturesFolder != UUID.Zero) | ||
2007 | // uploadComplete.new_texture_folder_id = m_texturesFolder; | ||
2008 | uploadComplete.state = "complete"; | ||
2009 | } | ||
2010 | else | ||
2011 | { | ||
2012 | LLSDAssetUploadError resperror = new LLSDAssetUploadError(); | ||
2013 | resperror.message = m_error; | ||
2014 | resperror.identifier = inv; | ||
2015 | |||
2016 | uploadComplete.error = resperror; | ||
2017 | uploadComplete.state = "failed"; | ||
2018 | } | ||
2019 | } | ||
2020 | |||
2021 | res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||
1086 | return res; | 2022 | return res; |
1087 | } | 2023 | } |
1088 | 2024 | ||
2025 | private void TimedOut(object sender, ElapsedEventArgs args) | ||
2026 | { | ||
2027 | m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload"); | ||
2028 | httpListener.RemoveStreamHandler("POST", uploaderPath); | ||
2029 | } | ||
2030 | |||
1089 | ///Left this in and commented in case there are unforseen issues | 2031 | ///Left this in and commented in case there are unforseen issues |
1090 | //private void SaveAssetToFile(string filename, byte[] data) | 2032 | //private void SaveAssetToFile(string filename, byte[] data) |
1091 | //{ | 2033 | //{ |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs index c241075..683c3d5 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs | |||
@@ -63,7 +63,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
63 | { | 63 | { |
64 | } | 64 | } |
65 | 65 | ||
66 | public void Close() { } | 66 | public void Close() { } |
67 | 67 | ||
68 | public void AddRegion(Scene scene) | 68 | public void AddRegion(Scene scene) |
69 | { | 69 | { |
@@ -80,11 +80,11 @@ namespace OpenSim.Region.ClientStack.Linden | |||
80 | } | 80 | } |
81 | 81 | ||
82 | public void PostInitialise() { } | 82 | public void PostInitialise() { } |
83 | #endregion | 83 | #endregion |
84 | 84 | ||
85 | private void OnRegisterCaps(UUID agentID, Caps caps) | 85 | private void OnRegisterCaps(UUID agentID, Caps caps) |
86 | { | 86 | { |
87 | new BunchOfCaps(m_Scene, caps); | 87 | new BunchOfCaps(m_Scene, agentID, caps); |
88 | } | 88 | } |
89 | 89 | ||
90 | } | 90 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs new file mode 100644 index 0000000..eb1ab45 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs | |||
@@ -0,0 +1,746 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | |||
29 | using System; | ||
30 | using System.IO; | ||
31 | using System.Collections; | ||
32 | using System.Collections.Generic; | ||
33 | using System.Text; | ||
34 | |||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | |||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.Framework; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using OpenSim.Framework.Capabilities; | ||
42 | |||
43 | using ComponentAce.Compression.Libs.zlib; | ||
44 | |||
45 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; | ||
46 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
47 | |||
48 | using Nini.Config; | ||
49 | |||
50 | namespace OpenSim.Region.ClientStack.Linden | ||
51 | { | ||
52 | public struct ModelPrimLimits | ||
53 | { | ||
54 | |||
55 | } | ||
56 | |||
57 | public class ModelCost | ||
58 | { | ||
59 | |||
60 | // upload fee defaults | ||
61 | // fees are normalized to 1.0 | ||
62 | // this parameters scale them to basic cost ( so 1.0 translates to 10 ) | ||
63 | |||
64 | public float ModelMeshCostFactor = 0.0f; // scale total cost relative to basic (excluding textures) | ||
65 | public float ModelTextureCostFactor = 1.0f; // scale textures fee to basic. | ||
66 | public float ModelMinCostFactor = 0.0f; // 0.5f; // minimum total model free excluding textures | ||
67 | |||
68 | // itens costs in normalized values | ||
69 | // ie will be multiplied by basicCost and factors above | ||
70 | public float primCreationCost = 0.002f; // extra cost for each prim creation overhead | ||
71 | // weigthed size to normalized cost | ||
72 | public float bytecost = 1e-5f; | ||
73 | |||
74 | // mesh upload fees based on compressed data sizes | ||
75 | // several data sections are counted more that once | ||
76 | // to promote user optimization | ||
77 | // following parameters control how many extra times they are added | ||
78 | // to global size. | ||
79 | // LOD meshs | ||
80 | const float medSizeWth = 1f; // 2x | ||
81 | const float lowSizeWth = 1.5f; // 2.5x | ||
82 | const float lowestSizeWth = 2f; // 3x | ||
83 | // favor potencially physical optimized meshs versus automatic decomposition | ||
84 | const float physMeshSizeWth = 6f; // counts 7x | ||
85 | const float physHullSizeWth = 8f; // counts 9x | ||
86 | |||
87 | // stream cost area factors | ||
88 | // more or less like SL | ||
89 | const float highLodFactor = 17.36f; | ||
90 | const float midLodFactor = 277.78f; | ||
91 | const float lowLodFactor = 1111.11f; | ||
92 | |||
93 | // physics cost is below, identical to SL, assuming shape type convex | ||
94 | // server cost is below identical to SL assuming non scripted non physical object | ||
95 | |||
96 | // internal | ||
97 | const int bytesPerCoord = 6; // 3 coords, 2 bytes per each | ||
98 | |||
99 | // control prims dimensions | ||
100 | public float PrimScaleMin = 0.001f; | ||
101 | public float NonPhysicalPrimScaleMax = 256f; | ||
102 | public float PhysicalPrimScaleMax = 10f; | ||
103 | public int ObjectLinkedPartsMax = 512; | ||
104 | |||
105 | |||
106 | public ModelCost(Scene scene) | ||
107 | { | ||
108 | PrimScaleMin = scene.m_minNonphys; | ||
109 | NonPhysicalPrimScaleMax = scene.m_maxNonphys; | ||
110 | PhysicalPrimScaleMax = scene.m_maxPhys; | ||
111 | ObjectLinkedPartsMax = scene.m_linksetCapacity; | ||
112 | } | ||
113 | |||
114 | public void Econfig(IConfig EconomyConfig) | ||
115 | { | ||
116 | ModelMeshCostFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", ModelMeshCostFactor); | ||
117 | ModelTextureCostFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", ModelTextureCostFactor); | ||
118 | ModelMinCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", ModelMinCostFactor); | ||
119 | // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost | ||
120 | primCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", primCreationCost); | ||
121 | bytecost = EconomyConfig.GetFloat("ModelMeshByteCost", bytecost); | ||
122 | } | ||
123 | |||
124 | // storage for a single mesh asset cost parameters | ||
125 | private class ameshCostParam | ||
126 | { | ||
127 | // LOD sizes for size dependent streaming cost | ||
128 | public int highLODSize; | ||
129 | public int medLODSize; | ||
130 | public int lowLODSize; | ||
131 | public int lowestLODSize; | ||
132 | // normalized fee based on compressed data sizes | ||
133 | public float costFee; | ||
134 | // physics cost | ||
135 | public float physicsCost; | ||
136 | } | ||
137 | |||
138 | // calculates a mesh model costs | ||
139 | // returns false on error, with a reason on parameter error | ||
140 | // resources input LLSD request | ||
141 | // basicCost input region assets upload cost | ||
142 | // totalcost returns model total upload fee | ||
143 | // meshcostdata returns detailed costs for viewer | ||
144 | // avatarSkeleton if mesh includes a avatar skeleton | ||
145 | // useAvatarCollider if we should use physics mesh for avatar | ||
146 | public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost, | ||
147 | LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning) | ||
148 | { | ||
149 | totalcost = 0; | ||
150 | error = string.Empty; | ||
151 | |||
152 | bool avatarSkeleton = false; | ||
153 | |||
154 | if (resources == null || | ||
155 | resources.instance_list == null || | ||
156 | resources.instance_list.Array.Count == 0) | ||
157 | { | ||
158 | error = "missing model information."; | ||
159 | return false; | ||
160 | } | ||
161 | |||
162 | int numberInstances = resources.instance_list.Array.Count; | ||
163 | |||
164 | if (ObjectLinkedPartsMax != 0 && numberInstances > ObjectLinkedPartsMax) | ||
165 | { | ||
166 | error = "Model would have more than " + ObjectLinkedPartsMax.ToString() + " linked prims"; | ||
167 | return false; | ||
168 | } | ||
169 | |||
170 | meshcostdata.model_streaming_cost = 0.0; | ||
171 | meshcostdata.simulation_cost = 0.0; | ||
172 | meshcostdata.physics_cost = 0.0; | ||
173 | meshcostdata.resource_cost = 0.0; | ||
174 | |||
175 | meshcostdata.upload_price_breakdown.mesh_instance = 0; | ||
176 | meshcostdata.upload_price_breakdown.mesh_physics = 0; | ||
177 | meshcostdata.upload_price_breakdown.mesh_streaming = 0; | ||
178 | meshcostdata.upload_price_breakdown.model = 0; | ||
179 | |||
180 | int itmp; | ||
181 | |||
182 | // textures cost | ||
183 | if (resources.texture_list != null && resources.texture_list.Array.Count > 0) | ||
184 | { | ||
185 | float textures_cost = (float)(resources.texture_list.Array.Count * basicCost); | ||
186 | textures_cost *= ModelTextureCostFactor; | ||
187 | |||
188 | itmp = (int)(textures_cost + 0.5f); // round | ||
189 | meshcostdata.upload_price_breakdown.texture = itmp; | ||
190 | totalcost += itmp; | ||
191 | } | ||
192 | |||
193 | // meshs assets cost | ||
194 | float meshsfee = 0; | ||
195 | int numberMeshs = 0; | ||
196 | bool haveMeshs = false; | ||
197 | |||
198 | bool curskeleton; | ||
199 | bool curAvatarPhys; | ||
200 | |||
201 | List<ameshCostParam> meshsCosts = new List<ameshCostParam>(); | ||
202 | |||
203 | if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0) | ||
204 | { | ||
205 | numberMeshs = resources.mesh_list.Array.Count; | ||
206 | |||
207 | for (int i = 0; i < numberMeshs; i++) | ||
208 | { | ||
209 | ameshCostParam curCost = new ameshCostParam(); | ||
210 | byte[] data = (byte[])resources.mesh_list.Array[i]; | ||
211 | |||
212 | if (!MeshCost(data, curCost,out curskeleton, out curAvatarPhys, out error)) | ||
213 | { | ||
214 | return false; | ||
215 | } | ||
216 | |||
217 | if (curskeleton) | ||
218 | { | ||
219 | if (avatarSkeleton) | ||
220 | { | ||
221 | error = "model can only contain a avatar skeleton"; | ||
222 | return false; | ||
223 | } | ||
224 | avatarSkeleton = true; | ||
225 | } | ||
226 | meshsCosts.Add(curCost); | ||
227 | meshsfee += curCost.costFee; | ||
228 | } | ||
229 | haveMeshs = true; | ||
230 | } | ||
231 | |||
232 | // instances (prims) cost | ||
233 | |||
234 | |||
235 | int mesh; | ||
236 | int skipedSmall = 0; | ||
237 | for (int i = 0; i < numberInstances; i++) | ||
238 | { | ||
239 | Hashtable inst = (Hashtable)resources.instance_list.Array[i]; | ||
240 | |||
241 | ArrayList ascale = (ArrayList)inst["scale"]; | ||
242 | Vector3 scale; | ||
243 | double tmp; | ||
244 | tmp = (double)ascale[0]; | ||
245 | scale.X = (float)tmp; | ||
246 | tmp = (double)ascale[1]; | ||
247 | scale.Y = (float)tmp; | ||
248 | tmp = (double)ascale[2]; | ||
249 | scale.Z = (float)tmp; | ||
250 | |||
251 | if (scale.X < PrimScaleMin || scale.Y < PrimScaleMin || scale.Z < PrimScaleMin) | ||
252 | { | ||
253 | skipedSmall++; | ||
254 | continue; | ||
255 | } | ||
256 | |||
257 | if (scale.X > NonPhysicalPrimScaleMax || scale.Y > NonPhysicalPrimScaleMax || scale.Z > NonPhysicalPrimScaleMax) | ||
258 | { | ||
259 | error = "Model contains parts with sides larger than " + NonPhysicalPrimScaleMax.ToString() + "m. Please ajust scale"; | ||
260 | return false; | ||
261 | } | ||
262 | |||
263 | if (haveMeshs && inst.ContainsKey("mesh")) | ||
264 | { | ||
265 | mesh = (int)inst["mesh"]; | ||
266 | |||
267 | if (mesh >= numberMeshs) | ||
268 | { | ||
269 | error = "Incoerent model information."; | ||
270 | return false; | ||
271 | } | ||
272 | |||
273 | // streamming cost | ||
274 | |||
275 | float sqdiam = scale.LengthSquared(); | ||
276 | |||
277 | ameshCostParam curCost = meshsCosts[mesh]; | ||
278 | float mesh_streaming = streamingCost(curCost, sqdiam); | ||
279 | |||
280 | meshcostdata.model_streaming_cost += mesh_streaming; | ||
281 | meshcostdata.physics_cost += curCost.physicsCost; | ||
282 | } | ||
283 | else // instance as no mesh ?? | ||
284 | { | ||
285 | // to do later if needed | ||
286 | meshcostdata.model_streaming_cost += 0.5f; | ||
287 | meshcostdata.physics_cost += 1.0f; | ||
288 | } | ||
289 | |||
290 | // assume unscripted and static prim server cost | ||
291 | meshcostdata.simulation_cost += 0.5f; | ||
292 | // charge for prims creation | ||
293 | meshsfee += primCreationCost; | ||
294 | } | ||
295 | |||
296 | if (skipedSmall > 0) | ||
297 | { | ||
298 | if (skipedSmall > numberInstances / 2) | ||
299 | { | ||
300 | error = "Model contains too many prims smaller than " + PrimScaleMin.ToString() + | ||
301 | "m minimum allowed size. Please check scalling"; | ||
302 | return false; | ||
303 | } | ||
304 | else | ||
305 | warning += skipedSmall.ToString() + " of the requested " +numberInstances.ToString() + | ||
306 | " model prims will not upload because they are smaller than " + PrimScaleMin.ToString() + | ||
307 | "m minimum allowed size. Please check scalling "; | ||
308 | } | ||
309 | |||
310 | if (meshcostdata.physics_cost <= meshcostdata.model_streaming_cost) | ||
311 | meshcostdata.resource_cost = meshcostdata.model_streaming_cost; | ||
312 | else | ||
313 | meshcostdata.resource_cost = meshcostdata.physics_cost; | ||
314 | |||
315 | if (meshcostdata.resource_cost < meshcostdata.simulation_cost) | ||
316 | meshcostdata.resource_cost = meshcostdata.simulation_cost; | ||
317 | |||
318 | // scale cost | ||
319 | // at this point a cost of 1.0 whould mean basic cost | ||
320 | meshsfee *= ModelMeshCostFactor; | ||
321 | |||
322 | if (meshsfee < ModelMinCostFactor) | ||
323 | meshsfee = ModelMinCostFactor; | ||
324 | |||
325 | // actually scale it to basic cost | ||
326 | meshsfee *= (float)basicCost; | ||
327 | |||
328 | meshsfee += 0.5f; // rounding | ||
329 | |||
330 | totalcost += (int)meshsfee; | ||
331 | |||
332 | // breakdown prices | ||
333 | // don't seem to be in use so removed code for now | ||
334 | |||
335 | return true; | ||
336 | } | ||
337 | |||
338 | // single mesh asset cost | ||
339 | private bool MeshCost(byte[] data, ameshCostParam cost,out bool skeleton, out bool avatarPhys, out string error) | ||
340 | { | ||
341 | cost.highLODSize = 0; | ||
342 | cost.medLODSize = 0; | ||
343 | cost.lowLODSize = 0; | ||
344 | cost.lowestLODSize = 0; | ||
345 | cost.physicsCost = 0.0f; | ||
346 | cost.costFee = 0.0f; | ||
347 | |||
348 | error = string.Empty; | ||
349 | |||
350 | skeleton = false; | ||
351 | avatarPhys = false; | ||
352 | |||
353 | if (data == null || data.Length == 0) | ||
354 | { | ||
355 | error = "Missing model information."; | ||
356 | return false; | ||
357 | } | ||
358 | |||
359 | OSD meshOsd = null; | ||
360 | int start = 0; | ||
361 | |||
362 | error = "Invalid model data"; | ||
363 | |||
364 | using (MemoryStream ms = new MemoryStream(data)) | ||
365 | { | ||
366 | try | ||
367 | { | ||
368 | OSD osd = OSDParser.DeserializeLLSDBinary(ms); | ||
369 | if (osd is OSDMap) | ||
370 | meshOsd = (OSDMap)osd; | ||
371 | else | ||
372 | return false; | ||
373 | } | ||
374 | catch | ||
375 | { | ||
376 | return false; | ||
377 | } | ||
378 | start = (int)ms.Position; | ||
379 | } | ||
380 | |||
381 | OSDMap map = (OSDMap)meshOsd; | ||
382 | OSDMap tmpmap; | ||
383 | |||
384 | int highlod_size = 0; | ||
385 | int medlod_size = 0; | ||
386 | int lowlod_size = 0; | ||
387 | int lowestlod_size = 0; | ||
388 | int skin_size = 0; | ||
389 | |||
390 | int hulls_size = 0; | ||
391 | int phys_nhulls; | ||
392 | int phys_hullsvertices = 0; | ||
393 | |||
394 | int physmesh_size = 0; | ||
395 | int phys_ntriangles = 0; | ||
396 | |||
397 | int submesh_offset = -1; | ||
398 | |||
399 | if (map.ContainsKey("skeleton")) | ||
400 | { | ||
401 | tmpmap = (OSDMap)map["skeleton"]; | ||
402 | if (tmpmap.ContainsKey("offset") && tmpmap.ContainsKey("size")) | ||
403 | { | ||
404 | int sksize = tmpmap["size"].AsInteger(); | ||
405 | if(sksize > 0) | ||
406 | skeleton = true; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | if (map.ContainsKey("physics_convex")) | ||
411 | { | ||
412 | tmpmap = (OSDMap)map["physics_convex"]; | ||
413 | if (tmpmap.ContainsKey("offset")) | ||
414 | submesh_offset = tmpmap["offset"].AsInteger() + start; | ||
415 | if (tmpmap.ContainsKey("size")) | ||
416 | hulls_size = tmpmap["size"].AsInteger(); | ||
417 | } | ||
418 | |||
419 | if (submesh_offset < 0 || hulls_size == 0) | ||
420 | { | ||
421 | error = "Missing physics_convex block"; | ||
422 | return false; | ||
423 | } | ||
424 | |||
425 | if (!hulls(data, submesh_offset, hulls_size, out phys_hullsvertices, out phys_nhulls)) | ||
426 | { | ||
427 | error = "Bad physics_convex block"; | ||
428 | return false; | ||
429 | } | ||
430 | |||
431 | submesh_offset = -1; | ||
432 | |||
433 | // only look for LOD meshs sizes | ||
434 | |||
435 | if (map.ContainsKey("high_lod")) | ||
436 | { | ||
437 | tmpmap = (OSDMap)map["high_lod"]; | ||
438 | // see at least if there is a offset for this one | ||
439 | if (tmpmap.ContainsKey("offset")) | ||
440 | submesh_offset = tmpmap["offset"].AsInteger() + start; | ||
441 | if (tmpmap.ContainsKey("size")) | ||
442 | highlod_size = tmpmap["size"].AsInteger(); | ||
443 | } | ||
444 | |||
445 | if (submesh_offset < 0 || highlod_size <= 0) | ||
446 | { | ||
447 | error = "Missing high_lod block"; | ||
448 | return false; | ||
449 | } | ||
450 | |||
451 | bool haveprev = true; | ||
452 | |||
453 | if (map.ContainsKey("medium_lod")) | ||
454 | { | ||
455 | tmpmap = (OSDMap)map["medium_lod"]; | ||
456 | if (tmpmap.ContainsKey("size")) | ||
457 | medlod_size = tmpmap["size"].AsInteger(); | ||
458 | else | ||
459 | haveprev = false; | ||
460 | } | ||
461 | |||
462 | if (haveprev && map.ContainsKey("low_lod")) | ||
463 | { | ||
464 | tmpmap = (OSDMap)map["low_lod"]; | ||
465 | if (tmpmap.ContainsKey("size")) | ||
466 | lowlod_size = tmpmap["size"].AsInteger(); | ||
467 | else | ||
468 | haveprev = false; | ||
469 | } | ||
470 | |||
471 | if (haveprev && map.ContainsKey("lowest_lod")) | ||
472 | { | ||
473 | tmpmap = (OSDMap)map["lowest_lod"]; | ||
474 | if (tmpmap.ContainsKey("size")) | ||
475 | lowestlod_size = tmpmap["size"].AsInteger(); | ||
476 | } | ||
477 | |||
478 | if (map.ContainsKey("skin")) | ||
479 | { | ||
480 | tmpmap = (OSDMap)map["skin"]; | ||
481 | if (tmpmap.ContainsKey("size")) | ||
482 | skin_size = tmpmap["size"].AsInteger(); | ||
483 | } | ||
484 | |||
485 | cost.highLODSize = highlod_size; | ||
486 | cost.medLODSize = medlod_size; | ||
487 | cost.lowLODSize = lowlod_size; | ||
488 | cost.lowestLODSize = lowestlod_size; | ||
489 | |||
490 | submesh_offset = -1; | ||
491 | |||
492 | tmpmap = null; | ||
493 | if(map.ContainsKey("physics_mesh")) | ||
494 | tmpmap = (OSDMap)map["physics_mesh"]; | ||
495 | else if (map.ContainsKey("physics_shape")) // old naming | ||
496 | tmpmap = (OSDMap)map["physics_shape"]; | ||
497 | |||
498 | if(tmpmap != null) | ||
499 | { | ||
500 | if (tmpmap.ContainsKey("offset")) | ||
501 | submesh_offset = tmpmap["offset"].AsInteger() + start; | ||
502 | if (tmpmap.ContainsKey("size")) | ||
503 | physmesh_size = tmpmap["size"].AsInteger(); | ||
504 | |||
505 | if (submesh_offset >= 0 || physmesh_size > 0) | ||
506 | { | ||
507 | |||
508 | if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles)) | ||
509 | { | ||
510 | error = "Model data parsing error"; | ||
511 | return false; | ||
512 | } | ||
513 | } | ||
514 | } | ||
515 | |||
516 | // upload is done in convex shape type so only one hull | ||
517 | phys_hullsvertices++; | ||
518 | cost.physicsCost = 0.04f * phys_hullsvertices; | ||
519 | |||
520 | float sfee; | ||
521 | |||
522 | sfee = data.Length; // start with total compressed data size | ||
523 | |||
524 | // penalize lod meshs that should be more builder optimized | ||
525 | sfee += medSizeWth * medlod_size; | ||
526 | sfee += lowSizeWth * lowlod_size; | ||
527 | sfee += lowestSizeWth * lowlod_size; | ||
528 | |||
529 | // physics | ||
530 | // favor potencial optimized meshs versus automatic decomposition | ||
531 | if (physmesh_size != 0) | ||
532 | sfee += physMeshSizeWth * (physmesh_size + hulls_size / 4); // reduce cost of mandatory convex hull | ||
533 | else | ||
534 | sfee += physHullSizeWth * hulls_size; | ||
535 | |||
536 | // bytes to money | ||
537 | sfee *= bytecost; | ||
538 | |||
539 | cost.costFee = sfee; | ||
540 | return true; | ||
541 | } | ||
542 | |||
543 | // parses a LOD or physics mesh component | ||
544 | private bool submesh(byte[] data, int offset, int size, out int ntriangles) | ||
545 | { | ||
546 | ntriangles = 0; | ||
547 | |||
548 | OSD decodedMeshOsd = new OSD(); | ||
549 | byte[] meshBytes = new byte[size]; | ||
550 | System.Buffer.BlockCopy(data, offset, meshBytes, 0, size); | ||
551 | try | ||
552 | { | ||
553 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | ||
554 | { | ||
555 | using (MemoryStream outMs = new MemoryStream()) | ||
556 | { | ||
557 | using (ZOutputStream zOut = new ZOutputStream(outMs)) | ||
558 | { | ||
559 | byte[] readBuffer = new byte[4096]; | ||
560 | int readLen = 0; | ||
561 | while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) | ||
562 | { | ||
563 | zOut.Write(readBuffer, 0, readLen); | ||
564 | } | ||
565 | zOut.Flush(); | ||
566 | outMs.Seek(0, SeekOrigin.Begin); | ||
567 | |||
568 | byte[] decompressedBuf = outMs.GetBuffer(); | ||
569 | decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); | ||
570 | } | ||
571 | } | ||
572 | } | ||
573 | } | ||
574 | catch | ||
575 | { | ||
576 | return false; | ||
577 | } | ||
578 | |||
579 | OSDArray decodedMeshOsdArray = null; | ||
580 | |||
581 | byte[] dummy; | ||
582 | |||
583 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; | ||
584 | foreach (OSD subMeshOsd in decodedMeshOsdArray) | ||
585 | { | ||
586 | if (subMeshOsd is OSDMap) | ||
587 | { | ||
588 | OSDMap subtmpmap = (OSDMap)subMeshOsd; | ||
589 | if (subtmpmap.ContainsKey("NoGeometry") && ((OSDBoolean)subtmpmap["NoGeometry"])) | ||
590 | continue; | ||
591 | |||
592 | if (!subtmpmap.ContainsKey("Position")) | ||
593 | return false; | ||
594 | |||
595 | if (subtmpmap.ContainsKey("TriangleList")) | ||
596 | { | ||
597 | dummy = subtmpmap["TriangleList"].AsBinary(); | ||
598 | ntriangles += dummy.Length / bytesPerCoord; | ||
599 | } | ||
600 | else | ||
601 | return false; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | return true; | ||
606 | } | ||
607 | |||
608 | // parses convex hulls component | ||
609 | private bool hulls(byte[] data, int offset, int size, out int nvertices, out int nhulls) | ||
610 | { | ||
611 | nvertices = 0; | ||
612 | nhulls = 1; | ||
613 | |||
614 | OSD decodedMeshOsd = new OSD(); | ||
615 | byte[] meshBytes = new byte[size]; | ||
616 | System.Buffer.BlockCopy(data, offset, meshBytes, 0, size); | ||
617 | try | ||
618 | { | ||
619 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | ||
620 | { | ||
621 | using (MemoryStream outMs = new MemoryStream()) | ||
622 | { | ||
623 | using (ZOutputStream zOut = new ZOutputStream(outMs)) | ||
624 | { | ||
625 | byte[] readBuffer = new byte[4096]; | ||
626 | int readLen = 0; | ||
627 | while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) | ||
628 | { | ||
629 | zOut.Write(readBuffer, 0, readLen); | ||
630 | } | ||
631 | zOut.Flush(); | ||
632 | outMs.Seek(0, SeekOrigin.Begin); | ||
633 | |||
634 | byte[] decompressedBuf = outMs.GetBuffer(); | ||
635 | decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); | ||
636 | } | ||
637 | } | ||
638 | } | ||
639 | } | ||
640 | catch | ||
641 | { | ||
642 | return false; | ||
643 | } | ||
644 | |||
645 | OSDMap cmap = (OSDMap)decodedMeshOsd; | ||
646 | if (cmap == null) | ||
647 | return false; | ||
648 | |||
649 | byte[] dummy; | ||
650 | |||
651 | // must have one of this | ||
652 | if (cmap.ContainsKey("BoundingVerts")) | ||
653 | { | ||
654 | dummy = cmap["BoundingVerts"].AsBinary(); | ||
655 | nvertices = dummy.Length / bytesPerCoord; | ||
656 | } | ||
657 | else | ||
658 | return false; | ||
659 | |||
660 | /* upload is done with convex shape type | ||
661 | if (cmap.ContainsKey("HullList")) | ||
662 | { | ||
663 | dummy = cmap["HullList"].AsBinary(); | ||
664 | nhulls += dummy.Length; | ||
665 | } | ||
666 | |||
667 | |||
668 | if (cmap.ContainsKey("Positions")) | ||
669 | { | ||
670 | dummy = cmap["Positions"].AsBinary(); | ||
671 | nvertices = dummy.Length / bytesPerCoord; | ||
672 | } | ||
673 | */ | ||
674 | |||
675 | return true; | ||
676 | } | ||
677 | |||
678 | // returns streaming cost from on mesh LODs sizes in curCost and square of prim size length | ||
679 | private float streamingCost(ameshCostParam curCost, float sqdiam) | ||
680 | { | ||
681 | // compute efective areas | ||
682 | float ma = 262144f; | ||
683 | |||
684 | float mh = sqdiam * highLodFactor; | ||
685 | if (mh > ma) | ||
686 | mh = ma; | ||
687 | float mm = sqdiam * midLodFactor; | ||
688 | if (mm > ma) | ||
689 | mm = ma; | ||
690 | |||
691 | float ml = sqdiam * lowLodFactor; | ||
692 | if (ml > ma) | ||
693 | ml = ma; | ||
694 | |||
695 | float mlst = ma; | ||
696 | |||
697 | mlst -= ml; | ||
698 | ml -= mm; | ||
699 | mm -= mh; | ||
700 | |||
701 | if (mlst < 1.0f) | ||
702 | mlst = 1.0f; | ||
703 | if (ml < 1.0f) | ||
704 | ml = 1.0f; | ||
705 | if (mm < 1.0f) | ||
706 | mm = 1.0f; | ||
707 | if (mh < 1.0f) | ||
708 | mh = 1.0f; | ||
709 | |||
710 | ma = mlst + ml + mm + mh; | ||
711 | |||
712 | // get LODs compressed sizes | ||
713 | // giving 384 bytes bonus | ||
714 | int lst = curCost.lowestLODSize - 384; | ||
715 | int l = curCost.lowLODSize - 384; | ||
716 | int m = curCost.medLODSize - 384; | ||
717 | int h = curCost.highLODSize - 384; | ||
718 | |||
719 | // use previus higher LOD size on missing ones | ||
720 | if (m <= 0) | ||
721 | m = h; | ||
722 | if (l <= 0) | ||
723 | l = m; | ||
724 | if (lst <= 0) | ||
725 | lst = l; | ||
726 | |||
727 | // force minumum sizes | ||
728 | if (lst < 16) | ||
729 | lst = 16; | ||
730 | if (l < 16) | ||
731 | l = 16; | ||
732 | if (m < 16) | ||
733 | m = 16; | ||
734 | if (h < 16) | ||
735 | h = 16; | ||
736 | |||
737 | // compute cost weighted by relative effective areas | ||
738 | float cost = (float)lst * mlst + (float)l * ml + (float)m * mm + (float)h * mh; | ||
739 | cost /= ma; | ||
740 | |||
741 | cost *= 0.004f; // overall tunning parameter | ||
742 | |||
743 | return cost; | ||
744 | } | ||
745 | } | ||
746 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 9b9f6a7..7c9a1c4 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | |||
@@ -74,13 +74,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
74 | private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000); | 74 | private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000); |
75 | 75 | ||
76 | protected Scene m_scene; | 76 | protected Scene m_scene; |
77 | 77 | ||
78 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); | 78 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); |
79 | 79 | ||
80 | private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); | 80 | private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); |
81 | private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>(); | ||
82 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); | 81 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); |
83 | 82 | ||
84 | #region INonSharedRegionModule methods | 83 | #region INonSharedRegionModule methods |
85 | public virtual void Initialise(IConfigSource config) | 84 | public virtual void Initialise(IConfigSource config) |
86 | { | 85 | { |
@@ -171,7 +170,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
171 | foreach (KeyValuePair<UUID, Queue<OSD>> kvp in queues) | 170 | foreach (KeyValuePair<UUID, Queue<OSD>> kvp in queues) |
172 | { | 171 | { |
173 | MainConsole.Instance.OutputFormat( | 172 | MainConsole.Instance.OutputFormat( |
174 | "For agent {0} there are {1} messages queued for send.", | 173 | "For agent {0} there are {1} messages queued for send.", |
175 | kvp.Key, kvp.Value.Count); | 174 | kvp.Key, kvp.Value.Count); |
176 | } | 175 | } |
177 | } | 176 | } |
@@ -190,7 +189,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
190 | { | 189 | { |
191 | if (DebugLevel > 0) | 190 | if (DebugLevel > 0) |
192 | m_log.DebugFormat( | 191 | m_log.DebugFormat( |
193 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", | 192 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", |
194 | agentId, m_scene.RegionInfo.RegionName); | 193 | agentId, m_scene.RegionInfo.RegionName); |
195 | 194 | ||
196 | queues[agentId] = new Queue<OSD>(); | 195 | queues[agentId] = new Queue<OSD>(); |
@@ -201,6 +200,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
201 | } | 200 | } |
202 | 201 | ||
203 | /// <summary> | 202 | /// <summary> |
203 | |||
204 | /// May return a null queue | 204 | /// May return a null queue |
205 | /// </summary> | 205 | /// </summary> |
206 | /// <param name="agentId"></param> | 206 | /// <param name="agentId"></param> |
@@ -231,26 +231,20 @@ namespace OpenSim.Region.ClientStack.Linden | |||
231 | lock (queue) | 231 | lock (queue) |
232 | queue.Enqueue(ev); | 232 | queue.Enqueue(ev); |
233 | } | 233 | } |
234 | else if (DebugLevel > 0) | 234 | else |
235 | { | 235 | { |
236 | ScenePresence sp = m_scene.GetScenePresence(avatarID); | ||
237 | |||
238 | // This assumes that an NPC should never have a queue. | ||
239 | if (sp != null && sp.PresenceType != PresenceType.Npc) | ||
240 | { | ||
241 | OSDMap evMap = (OSDMap)ev; | 236 | OSDMap evMap = (OSDMap)ev; |
242 | m_log.WarnFormat( | 237 | m_log.WarnFormat( |
243 | "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} {1} when placing message {2} in region {3}", | 238 | "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}", |
244 | sp.Name, sp.UUID, evMap["message"], m_scene.Name); | 239 | avatarID, evMap["message"], m_scene.Name); |
245 | } | ||
246 | } | 240 | } |
247 | } | 241 | } |
248 | catch (NullReferenceException e) | 242 | catch (NullReferenceException e) |
249 | { | 243 | { |
250 | m_log.Error("[EVENTQUEUE] Caught exception: " + e); | 244 | m_log.Error("[EVENTQUEUE] Caught exception: " + e); |
251 | return false; | 245 | return false; |
252 | } | 246 | } |
253 | 247 | ||
254 | return true; | 248 | return true; |
255 | } | 249 | } |
256 | 250 | ||
@@ -263,28 +257,13 @@ namespace OpenSim.Region.ClientStack.Linden | |||
263 | lock (queues) | 257 | lock (queues) |
264 | queues.Remove(agentID); | 258 | queues.Remove(agentID); |
265 | 259 | ||
266 | List<UUID> removeitems = new List<UUID>(); | ||
267 | lock (m_AvatarQueueUUIDMapping) | 260 | lock (m_AvatarQueueUUIDMapping) |
268 | m_AvatarQueueUUIDMapping.Remove(agentID); | 261 | m_AvatarQueueUUIDMapping.Remove(agentID); |
269 | 262 | ||
270 | UUID searchval = UUID.Zero; | 263 | lock (m_ids) |
271 | |||
272 | removeitems.Clear(); | ||
273 | |||
274 | lock (m_QueueUUIDAvatarMapping) | ||
275 | { | 264 | { |
276 | foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) | 265 | if (!m_ids.ContainsKey(agentID)) |
277 | { | 266 | m_ids.Remove(agentID); |
278 | searchval = m_QueueUUIDAvatarMapping[ky]; | ||
279 | |||
280 | if (searchval == agentID) | ||
281 | { | ||
282 | removeitems.Add(ky); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | foreach (UUID ky in removeitems) | ||
287 | m_QueueUUIDAvatarMapping.Remove(ky); | ||
288 | } | 267 | } |
289 | 268 | ||
290 | // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | 269 | // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); |
@@ -309,55 +288,95 @@ namespace OpenSim.Region.ClientStack.Linden | |||
309 | "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", | 288 | "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", |
310 | agentID, caps, m_scene.RegionInfo.RegionName); | 289 | agentID, caps, m_scene.RegionInfo.RegionName); |
311 | 290 | ||
312 | // Let's instantiate a Queue for this agent right now | ||
313 | TryGetQueue(agentID); | ||
314 | |||
315 | UUID eventQueueGetUUID; | 291 | UUID eventQueueGetUUID; |
292 | Queue<OSD> queue; | ||
293 | Random rnd = new Random(Environment.TickCount); | ||
294 | int nrnd = rnd.Next(30000000); | ||
295 | if (nrnd < 0) | ||
296 | nrnd = -nrnd; | ||
316 | 297 | ||
317 | lock (m_AvatarQueueUUIDMapping) | 298 | lock (queues) |
318 | { | 299 | { |
319 | // Reuse open queues. The client does! | 300 | if (queues.ContainsKey(agentID)) |
320 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | 301 | queue = queues[agentID]; |
302 | else | ||
303 | queue = null; | ||
304 | |||
305 | if (queue == null) | ||
321 | { | 306 | { |
322 | //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); | 307 | queue = new Queue<OSD>(); |
323 | eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | 308 | queues[agentID] = queue; |
309 | |||
310 | // push markers to handle old responses still waiting | ||
311 | // this will cost at most viewer getting two forced noevents | ||
312 | // even being a new queue better be safe | ||
313 | queue.Enqueue(null); | ||
314 | queue.Enqueue(null); // one should be enough | ||
315 | |||
316 | lock (m_AvatarQueueUUIDMapping) | ||
317 | { | ||
318 | eventQueueGetUUID = UUID.Random(); | ||
319 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
320 | { | ||
321 | // oops this should not happen ? | ||
322 | m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID without a queue"); | ||
323 | eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | ||
324 | } | ||
325 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | ||
326 | } | ||
327 | lock (m_ids) | ||
328 | { | ||
329 | if (!m_ids.ContainsKey(agentID)) | ||
330 | m_ids.Add(agentID, nrnd); | ||
331 | else | ||
332 | m_ids[agentID] = nrnd; | ||
333 | } | ||
324 | } | 334 | } |
325 | else | 335 | else |
326 | { | 336 | { |
327 | eventQueueGetUUID = UUID.Random(); | 337 | // push markers to handle old responses still waiting |
328 | //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); | 338 | // this will cost at most viewer getting two forced noevents |
339 | // even being a new queue better be safe | ||
340 | queue.Enqueue(null); | ||
341 | queue.Enqueue(null); // one should be enough | ||
342 | |||
343 | // reuse or not to reuse TODO FIX | ||
344 | lock (m_AvatarQueueUUIDMapping) | ||
345 | { | ||
346 | // Reuse open queues. The client does! | ||
347 | // Its reuse caps path not queues those are been reused already | ||
348 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
349 | { | ||
350 | m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); | ||
351 | eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | ||
352 | } | ||
353 | else | ||
354 | { | ||
355 | eventQueueGetUUID = UUID.Random(); | ||
356 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | ||
357 | m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); | ||
358 | } | ||
359 | } | ||
360 | lock (m_ids) | ||
361 | { | ||
362 | // change to negative numbers so they are changed at end of sending first marker | ||
363 | // old data on a queue may be sent on a response for a new caps | ||
364 | // but at least will be sent with coerent IDs | ||
365 | if (!m_ids.ContainsKey(agentID)) | ||
366 | m_ids.Add(agentID, -nrnd); // should not happen | ||
367 | else | ||
368 | m_ids[agentID] = -m_ids[agentID]; | ||
369 | } | ||
329 | } | 370 | } |
330 | } | 371 | } |
331 | 372 | ||
332 | lock (m_QueueUUIDAvatarMapping) | ||
333 | { | ||
334 | if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID)) | ||
335 | m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID); | ||
336 | } | ||
337 | |||
338 | lock (m_AvatarQueueUUIDMapping) | ||
339 | { | ||
340 | if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
341 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | ||
342 | } | ||
343 | |||
344 | caps.RegisterPollHandler( | 373 | caps.RegisterPollHandler( |
345 | "EventQueueGet", | 374 | "EventQueueGet", |
346 | new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); | 375 | new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); |
347 | |||
348 | Random rnd = new Random(Environment.TickCount); | ||
349 | lock (m_ids) | ||
350 | { | ||
351 | if (!m_ids.ContainsKey(agentID)) | ||
352 | m_ids.Add(agentID, rnd.Next(30000000)); | ||
353 | } | ||
354 | } | 376 | } |
355 | 377 | ||
356 | public bool HasEvents(UUID requestID, UUID agentID) | 378 | public bool HasEvents(UUID requestID, UUID agentID) |
357 | { | 379 | { |
358 | // Don't use this, because of race conditions at agent closing time | ||
359 | //Queue<OSD> queue = TryGetQueue(agentID); | ||
360 | |||
361 | Queue<OSD> queue = GetQueue(agentID); | 380 | Queue<OSD> queue = GetQueue(agentID); |
362 | if (queue != null) | 381 | if (queue != null) |
363 | lock (queue) | 382 | lock (queue) |
@@ -366,7 +385,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
366 | return queue.Count > 0; | 385 | return queue.Count > 0; |
367 | } | 386 | } |
368 | 387 | ||
369 | return false; | 388 | //m_log.WarnFormat("POLLED FOR EVENTS BY {0} unknown agent", agentID); |
389 | return true; | ||
370 | } | 390 | } |
371 | 391 | ||
372 | /// <summary> | 392 | /// <summary> |
@@ -383,6 +403,10 @@ namespace OpenSim.Region.ClientStack.Linden | |||
383 | ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name); | 403 | ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name); |
384 | } | 404 | } |
385 | } | 405 | } |
406 | public void Drop(UUID requestID, UUID pAgentId) | ||
407 | { | ||
408 | // do nothing for now, hope client close will do it | ||
409 | } | ||
386 | 410 | ||
387 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) | 411 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) |
388 | { | 412 | { |
@@ -395,55 +419,65 @@ namespace OpenSim.Region.ClientStack.Linden | |||
395 | return NoEvents(requestID, pAgentId); | 419 | return NoEvents(requestID, pAgentId); |
396 | } | 420 | } |
397 | 421 | ||
398 | OSD element; | 422 | OSD element = null;; |
423 | OSDArray array = new OSDArray(); | ||
424 | int thisID = 0; | ||
425 | bool negativeID = false; | ||
426 | |||
399 | lock (queue) | 427 | lock (queue) |
400 | { | 428 | { |
401 | if (queue.Count == 0) | 429 | if (queue.Count == 0) |
402 | return NoEvents(requestID, pAgentId); | 430 | return NoEvents(requestID, pAgentId); |
403 | element = queue.Dequeue(); // 15s timeout | ||
404 | } | ||
405 | |||
406 | int thisID = 0; | ||
407 | lock (m_ids) | ||
408 | thisID = m_ids[pAgentId]; | ||
409 | 431 | ||
410 | OSDArray array = new OSDArray(); | 432 | lock (m_ids) |
411 | if (element == null) // didn't have an event in 15s | 433 | thisID = m_ids[pAgentId]; |
412 | { | ||
413 | // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
414 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
415 | //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName); | ||
416 | } | ||
417 | else | ||
418 | { | ||
419 | if (DebugLevel > 0) | ||
420 | LogOutboundDebugMessage(element, pAgentId); | ||
421 | 434 | ||
422 | array.Add(element); | 435 | if (thisID < 0) |
436 | { | ||
437 | negativeID = true; | ||
438 | thisID = -thisID; | ||
439 | } | ||
423 | 440 | ||
424 | lock (queue) | 441 | while (queue.Count > 0) |
425 | { | 442 | { |
426 | while (queue.Count > 0) | 443 | element = queue.Dequeue(); |
427 | { | 444 | // add elements until a marker is found |
428 | element = queue.Dequeue(); | 445 | // so they get into a response |
446 | if (element == null) | ||
447 | break; | ||
448 | if (DebugLevel > 0) | ||
449 | LogOutboundDebugMessage(element, pAgentId); | ||
450 | array.Add(element); | ||
451 | thisID++; | ||
452 | } | ||
453 | } | ||
429 | 454 | ||
430 | if (DebugLevel > 0) | 455 | OSDMap events = null; |
431 | LogOutboundDebugMessage(element, pAgentId); | ||
432 | 456 | ||
433 | array.Add(element); | 457 | if (array.Count > 0) |
434 | thisID++; | 458 | { |
435 | } | 459 | events = new OSDMap(); |
436 | } | 460 | events.Add("events", array); |
461 | events.Add("id", new OSDInteger(thisID)); | ||
437 | } | 462 | } |
438 | 463 | ||
439 | OSDMap events = new OSDMap(); | 464 | if (negativeID && element == null) |
440 | events.Add("events", array); | 465 | { |
466 | Random rnd = new Random(Environment.TickCount); | ||
467 | thisID = rnd.Next(30000000); | ||
468 | if (thisID < 0) | ||
469 | thisID = -thisID; | ||
470 | } | ||
441 | 471 | ||
442 | events.Add("id", new OSDInteger(thisID)); | ||
443 | lock (m_ids) | 472 | lock (m_ids) |
444 | { | 473 | { |
445 | m_ids[pAgentId] = thisID + 1; | 474 | m_ids[pAgentId] = thisID + 1; |
446 | } | 475 | } |
476 | |||
477 | // if there where no elements before a marker send a NoEvents | ||
478 | if (array.Count == 0) | ||
479 | return NoEvents(requestID, pAgentId); | ||
480 | |||
447 | Hashtable responsedata = new Hashtable(); | 481 | Hashtable responsedata = new Hashtable(); |
448 | responsedata["int_response_code"] = 200; | 482 | responsedata["int_response_code"] = 200; |
449 | responsedata["content_type"] = "application/xml"; | 483 | responsedata["content_type"] = "application/xml"; |
@@ -461,266 +495,18 @@ namespace OpenSim.Region.ClientStack.Linden | |||
461 | responsedata["content_type"] = "text/plain"; | 495 | responsedata["content_type"] = "text/plain"; |
462 | responsedata["keepalive"] = false; | 496 | responsedata["keepalive"] = false; |
463 | responsedata["reusecontext"] = false; | 497 | responsedata["reusecontext"] = false; |
464 | responsedata["str_response_string"] = "Upstream error: "; | 498 | responsedata["str_response_string"] = "<llsd></llsd>"; |
465 | responsedata["error_status_text"] = "Upstream error:"; | 499 | responsedata["error_status_text"] = "<llsd></llsd>"; |
466 | responsedata["http_protocol_version"] = "HTTP/1.0"; | 500 | responsedata["http_protocol_version"] = "HTTP/1.0"; |
467 | return responsedata; | 501 | return responsedata; |
468 | } | 502 | } |
469 | 503 | /* this is not a event message | |
470 | // public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps) | ||
471 | // { | ||
472 | // // TODO: this has to be redone to not busy-wait (and block the thread), | ||
473 | // // TODO: as soon as we have a non-blocking way to handle HTTP-requests. | ||
474 | // | ||
475 | //// if (m_log.IsDebugEnabled) | ||
476 | //// { | ||
477 | //// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ "; | ||
478 | //// foreach (object key in request.Keys) | ||
479 | //// { | ||
480 | //// debug += key.ToString() + "=" + request[key].ToString() + " "; | ||
481 | //// } | ||
482 | //// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name); | ||
483 | //// } | ||
484 | // | ||
485 | // Queue<OSD> queue = TryGetQueue(agentID); | ||
486 | // OSD element; | ||
487 | // | ||
488 | // lock (queue) | ||
489 | // element = queue.Dequeue(); // 15s timeout | ||
490 | // | ||
491 | // Hashtable responsedata = new Hashtable(); | ||
492 | // | ||
493 | // int thisID = 0; | ||
494 | // lock (m_ids) | ||
495 | // thisID = m_ids[agentID]; | ||
496 | // | ||
497 | // if (element == null) | ||
498 | // { | ||
499 | // //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName); | ||
500 | // if (thisID == -1) // close-request | ||
501 | // { | ||
502 | // m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName); | ||
503 | // responsedata["int_response_code"] = 404; //501; //410; //404; | ||
504 | // responsedata["content_type"] = "text/plain"; | ||
505 | // responsedata["keepalive"] = false; | ||
506 | // responsedata["str_response_string"] = "Closed EQG"; | ||
507 | // return responsedata; | ||
508 | // } | ||
509 | // responsedata["int_response_code"] = 502; | ||
510 | // responsedata["content_type"] = "text/plain"; | ||
511 | // responsedata["keepalive"] = false; | ||
512 | // responsedata["str_response_string"] = "Upstream error: "; | ||
513 | // responsedata["error_status_text"] = "Upstream error:"; | ||
514 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
515 | // return responsedata; | ||
516 | // } | ||
517 | // | ||
518 | // OSDArray array = new OSDArray(); | ||
519 | // if (element == null) // didn't have an event in 15s | ||
520 | // { | ||
521 | // // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
522 | // array.Add(EventQueueHelper.KeepAliveEvent()); | ||
523 | // //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | ||
524 | // } | ||
525 | // else | ||
526 | // { | ||
527 | // array.Add(element); | ||
528 | // | ||
529 | // if (element is OSDMap) | ||
530 | // { | ||
531 | // OSDMap ev = (OSDMap)element; | ||
532 | // m_log.DebugFormat( | ||
533 | // "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", | ||
534 | // ev["message"], m_scene.GetScenePresence(agentID).Name); | ||
535 | // } | ||
536 | // | ||
537 | // lock (queue) | ||
538 | // { | ||
539 | // while (queue.Count > 0) | ||
540 | // { | ||
541 | // element = queue.Dequeue(); | ||
542 | // | ||
543 | // if (element is OSDMap) | ||
544 | // { | ||
545 | // OSDMap ev = (OSDMap)element; | ||
546 | // m_log.DebugFormat( | ||
547 | // "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", | ||
548 | // ev["message"], m_scene.GetScenePresence(agentID).Name); | ||
549 | // } | ||
550 | // | ||
551 | // array.Add(element); | ||
552 | // thisID++; | ||
553 | // } | ||
554 | // } | ||
555 | // } | ||
556 | // | ||
557 | // OSDMap events = new OSDMap(); | ||
558 | // events.Add("events", array); | ||
559 | // | ||
560 | // events.Add("id", new OSDInteger(thisID)); | ||
561 | // lock (m_ids) | ||
562 | // { | ||
563 | // m_ids[agentID] = thisID + 1; | ||
564 | // } | ||
565 | // | ||
566 | // responsedata["int_response_code"] = 200; | ||
567 | // responsedata["content_type"] = "application/xml"; | ||
568 | // responsedata["keepalive"] = false; | ||
569 | // responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); | ||
570 | // | ||
571 | // m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); | ||
572 | // | ||
573 | // return responsedata; | ||
574 | // } | ||
575 | |||
576 | // public Hashtable EventQueuePath2(Hashtable request) | ||
577 | // { | ||
578 | // string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/",""); | ||
579 | // // pull off the last "/" in the path. | ||
580 | // Hashtable responsedata = new Hashtable(); | ||
581 | // capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
582 | // capuuid = capuuid.Replace("/CAPS/EQG/", ""); | ||
583 | // UUID AvatarID = UUID.Zero; | ||
584 | // UUID capUUID = UUID.Zero; | ||
585 | // | ||
586 | // // parse the path and search for the avatar with it registered | ||
587 | // if (UUID.TryParse(capuuid, out capUUID)) | ||
588 | // { | ||
589 | // lock (m_QueueUUIDAvatarMapping) | ||
590 | // { | ||
591 | // if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
592 | // { | ||
593 | // AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
594 | // } | ||
595 | // } | ||
596 | // | ||
597 | // if (AvatarID != UUID.Zero) | ||
598 | // { | ||
599 | // return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID)); | ||
600 | // } | ||
601 | // else | ||
602 | // { | ||
603 | // responsedata["int_response_code"] = 404; | ||
604 | // responsedata["content_type"] = "text/plain"; | ||
605 | // responsedata["keepalive"] = false; | ||
606 | // responsedata["str_response_string"] = "Not Found"; | ||
607 | // responsedata["error_status_text"] = "Not Found"; | ||
608 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
609 | // return responsedata; | ||
610 | // // return 404 | ||
611 | // } | ||
612 | // } | ||
613 | // else | ||
614 | // { | ||
615 | // responsedata["int_response_code"] = 404; | ||
616 | // responsedata["content_type"] = "text/plain"; | ||
617 | // responsedata["keepalive"] = false; | ||
618 | // responsedata["str_response_string"] = "Not Found"; | ||
619 | // responsedata["error_status_text"] = "Not Found"; | ||
620 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
621 | // return responsedata; | ||
622 | // // return 404 | ||
623 | // } | ||
624 | // } | ||
625 | |||
626 | public OSD EventQueueFallBack(string path, OSD request, string endpoint) | ||
627 | { | ||
628 | // This is a fallback element to keep the client from loosing EventQueueGet | ||
629 | // Why does CAPS fail sometimes!? | ||
630 | m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!"); | ||
631 | string capuuid = path.Replace("/CAPS/EQG/",""); | ||
632 | capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
633 | |||
634 | // UUID AvatarID = UUID.Zero; | ||
635 | UUID capUUID = UUID.Zero; | ||
636 | if (UUID.TryParse(capuuid, out capUUID)) | ||
637 | { | ||
638 | /* Don't remove this yet code cleaners! | ||
639 | * Still testing this! | ||
640 | * | ||
641 | lock (m_QueueUUIDAvatarMapping) | ||
642 | { | ||
643 | if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
644 | { | ||
645 | AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
646 | } | ||
647 | } | ||
648 | |||
649 | |||
650 | if (AvatarID != UUID.Zero) | ||
651 | { | ||
652 | // Repair the CAP! | ||
653 | //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID); | ||
654 | //string capsBase = "/CAPS/EQG/"; | ||
655 | //caps.RegisterHandler("EventQueueGet", | ||
656 | //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/", | ||
657 | //delegate(Hashtable m_dhttpMethod) | ||
658 | //{ | ||
659 | // return ProcessQueue(m_dhttpMethod, AvatarID, caps); | ||
660 | //})); | ||
661 | // start new ID sequence. | ||
662 | Random rnd = new Random(System.Environment.TickCount); | ||
663 | lock (m_ids) | ||
664 | { | ||
665 | if (!m_ids.ContainsKey(AvatarID)) | ||
666 | m_ids.Add(AvatarID, rnd.Next(30000000)); | ||
667 | } | ||
668 | |||
669 | |||
670 | int thisID = 0; | ||
671 | lock (m_ids) | ||
672 | thisID = m_ids[AvatarID]; | ||
673 | |||
674 | BlockingLLSDQueue queue = GetQueue(AvatarID); | ||
675 | OSDArray array = new OSDArray(); | ||
676 | LLSD element = queue.Dequeue(15000); // 15s timeout | ||
677 | if (element == null) | ||
678 | { | ||
679 | |||
680 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
681 | } | ||
682 | else | ||
683 | { | ||
684 | array.Add(element); | ||
685 | while (queue.Count() > 0) | ||
686 | { | ||
687 | array.Add(queue.Dequeue(1)); | ||
688 | thisID++; | ||
689 | } | ||
690 | } | ||
691 | OSDMap events = new OSDMap(); | ||
692 | events.Add("events", array); | ||
693 | |||
694 | events.Add("id", new LLSDInteger(thisID)); | ||
695 | |||
696 | lock (m_ids) | ||
697 | { | ||
698 | m_ids[AvatarID] = thisID + 1; | ||
699 | } | ||
700 | |||
701 | return events; | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | return new LLSD(); | ||
706 | } | ||
707 | * | ||
708 | */ | ||
709 | } | ||
710 | else | ||
711 | { | ||
712 | //return new LLSD(); | ||
713 | } | ||
714 | |||
715 | return new OSDString("shutdown404!"); | ||
716 | } | ||
717 | |||
718 | public void DisableSimulator(ulong handle, UUID avatarID) | 504 | public void DisableSimulator(ulong handle, UUID avatarID) |
719 | { | 505 | { |
720 | OSD item = EventQueueHelper.DisableSimulator(handle); | 506 | OSD item = EventQueueHelper.DisableSimulator(handle); |
721 | Enqueue(item, avatarID); | 507 | Enqueue(item, avatarID); |
722 | } | 508 | } |
723 | 509 | */ | |
724 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) | 510 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) |
725 | { | 511 | { |
726 | if (DebugLevel > 0) | 512 | if (DebugLevel > 0) |
@@ -732,7 +518,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
732 | } | 518 | } |
733 | 519 | ||
734 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath, | 520 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath, |
735 | ulong regionHandle, int regionSizeX, int regionSizeY) | 521 | ulong regionHandle, int regionSizeX, int regionSizeY) |
736 | { | 522 | { |
737 | if (DebugLevel > 0) | 523 | if (DebugLevel > 0) |
738 | m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, endPoint={2}, avatarID={3}", | 524 | m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, endPoint={2}, avatarID={3}", |
@@ -742,9 +528,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
742 | Enqueue(item, avatarID); | 528 | Enqueue(item, avatarID); |
743 | } | 529 | } |
744 | 530 | ||
745 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, | 531 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, |
746 | IPEndPoint regionExternalEndPoint, | 532 | IPEndPoint regionExternalEndPoint, |
747 | uint locationID, uint flags, string capsURL, | 533 | uint locationID, uint flags, string capsURL, |
748 | UUID avatarID, int regionSizeX, int regionSizeY) | 534 | UUID avatarID, int regionSizeX, int regionSizeY) |
749 | { | 535 | { |
750 | if (DebugLevel > 0) | 536 | if (DebugLevel > 0) |
@@ -774,33 +560,40 @@ namespace OpenSim.Region.ClientStack.Linden | |||
774 | uint timeStamp, bool offline, int parentEstateID, Vector3 position, | 560 | uint timeStamp, bool offline, int parentEstateID, Vector3 position, |
775 | uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) | 561 | uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) |
776 | { | 562 | { |
777 | OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, | 563 | OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, |
778 | timeStamp, offline, parentEstateID, position, ttl, transactionID, | 564 | timeStamp, offline, parentEstateID, position, ttl, transactionID, |
779 | fromGroup, binaryBucket); | 565 | fromGroup, binaryBucket); |
780 | Enqueue(item, toAgent); | 566 | Enqueue(item, toAgent); |
781 | //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item); | 567 | //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item); |
782 | 568 | ||
783 | } | 569 | } |
784 | 570 | ||
785 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, | 571 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, |
786 | bool isModerator, bool textMute) | 572 | bool isModerator, bool textMute, bool isEnterorLeave) |
787 | { | 573 | { |
788 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, | 574 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, |
789 | isModerator, textMute); | 575 | isModerator, textMute, isEnterorLeave); |
790 | Enqueue(item, fromAgent); | 576 | Enqueue(item, toAgent); |
791 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); | 577 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); |
792 | } | 578 | } |
793 | 579 | ||
580 | public void ChatterBoxForceClose(UUID toAgent, UUID sessionID, string reason) | ||
581 | { | ||
582 | OSD item = EventQueueHelper.ChatterBoxForceClose(sessionID, reason); | ||
583 | |||
584 | Enqueue(item, toAgent); | ||
585 | } | ||
586 | |||
794 | public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID) | 587 | public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID) |
795 | { | 588 | { |
796 | OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage); | 589 | OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage); |
797 | Enqueue(item, avatarID); | 590 | Enqueue(item, avatarID); |
798 | } | 591 | } |
799 | 592 | ||
800 | public void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID) | 593 | public void GroupMembershipData(UUID receiverAgent, GroupMembershipData[] data) |
801 | { | 594 | { |
802 | OSD item = EventQueueHelper.GroupMembership(groupUpdate); | 595 | OSD item = EventQueueHelper.GroupMembershipData(receiverAgent, data); |
803 | Enqueue(item, avatarID); | 596 | Enqueue(item, receiverAgent); |
804 | } | 597 | } |
805 | 598 | ||
806 | public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID) | 599 | public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID) |
@@ -827,4 +620,4 @@ namespace OpenSim.Region.ClientStack.Linden | |||
827 | Enqueue(item, avatarID); | 620 | Enqueue(item, avatarID); |
828 | } | 621 | } |
829 | } | 622 | } |
830 | } \ No newline at end of file | 623 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs index 384af74..461f776 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs | |||
@@ -32,6 +32,8 @@ using OpenMetaverse.Packets; | |||
32 | using OpenMetaverse.StructuredData; | 32 | using OpenMetaverse.StructuredData; |
33 | using OpenMetaverse.Messages.Linden; | 33 | using OpenMetaverse.Messages.Linden; |
34 | 34 | ||
35 | using OpenSim.Framework; | ||
36 | |||
35 | namespace OpenSim.Region.ClientStack.Linden | 37 | namespace OpenSim.Region.ClientStack.Linden |
36 | { | 38 | { |
37 | public class EventQueueHelper | 39 | public class EventQueueHelper |
@@ -76,9 +78,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
76 | 78 | ||
77 | llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); | 79 | llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); |
78 | llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); | 80 | llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); |
79 | llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); | 81 | llsdSimInfo.Add("Port", OSD.FromInteger(endPoint.Port)); |
80 | llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint) regionSizeX)); | 82 | llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX)); |
81 | llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint) regionSizeY)); | 83 | llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY)); |
82 | 84 | ||
83 | OSDArray arr = new OSDArray(1); | 85 | OSDArray arr = new OSDArray(1); |
84 | arr.Add(llsdSimInfo); | 86 | arr.Add(llsdSimInfo); |
@@ -88,7 +90,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
88 | 90 | ||
89 | return BuildEvent("EnableSimulator", llsdBody); | 91 | return BuildEvent("EnableSimulator", llsdBody); |
90 | } | 92 | } |
91 | 93 | /* | |
92 | public static OSD DisableSimulator(ulong handle) | 94 | public static OSD DisableSimulator(ulong handle) |
93 | { | 95 | { |
94 | //OSDMap llsdSimInfo = new OSDMap(1); | 96 | //OSDMap llsdSimInfo = new OSDMap(1); |
@@ -103,7 +105,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
103 | 105 | ||
104 | return BuildEvent("DisableSimulator", llsdBody); | 106 | return BuildEvent("DisableSimulator", llsdBody); |
105 | } | 107 | } |
106 | 108 | */ | |
107 | public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, | 109 | public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, |
108 | IPEndPoint newRegionExternalEndPoint, | 110 | IPEndPoint newRegionExternalEndPoint, |
109 | string capsURL, UUID agentID, UUID sessionID, | 111 | string capsURL, UUID agentID, UUID sessionID, |
@@ -157,6 +159,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
157 | uint locationID, uint flags, string capsURL, UUID agentID, | 159 | uint locationID, uint flags, string capsURL, UUID agentID, |
158 | int regionSizeX, int regionSizeY) | 160 | int regionSizeX, int regionSizeY) |
159 | { | 161 | { |
162 | // not sure why flags get overwritten here | ||
163 | if ((flags & (uint)TeleportFlags.IsFlying) != 0) | ||
164 | flags = (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.IsFlying; | ||
165 | else | ||
166 | flags = (uint)TeleportFlags.ViaLocation; | ||
167 | |||
160 | OSDMap info = new OSDMap(); | 168 | OSDMap info = new OSDMap(); |
161 | info.Add("AgentID", OSD.FromUUID(agentID)); | 169 | info.Add("AgentID", OSD.FromUUID(agentID)); |
162 | info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? | 170 | info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? |
@@ -165,7 +173,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
165 | info.Add("SimAccess", OSD.FromInteger(simAccess)); | 173 | info.Add("SimAccess", OSD.FromInteger(simAccess)); |
166 | info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); | 174 | info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); |
167 | info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); | 175 | info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); |
168 | info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation | 176 | // info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation |
177 | info.Add("TeleportFlags", OSD.FromUInteger(flags)); | ||
169 | info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX)); | 178 | info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX)); |
170 | info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY)); | 179 | info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY)); |
171 | 180 | ||
@@ -185,13 +194,13 @@ namespace OpenSim.Region.ClientStack.Linden | |||
185 | script.Add("ItemID", OSD.FromUUID(itemID)); | 194 | script.Add("ItemID", OSD.FromUUID(itemID)); |
186 | script.Add("Running", OSD.FromBoolean(running)); | 195 | script.Add("Running", OSD.FromBoolean(running)); |
187 | script.Add("Mono", OSD.FromBoolean(mono)); | 196 | script.Add("Mono", OSD.FromBoolean(mono)); |
188 | 197 | ||
189 | OSDArray scriptArr = new OSDArray(); | 198 | OSDArray scriptArr = new OSDArray(); |
190 | scriptArr.Add(script); | 199 | scriptArr.Add(script); |
191 | 200 | ||
192 | OSDMap body = new OSDMap(); | 201 | OSDMap body = new OSDMap(); |
193 | body.Add("Script", scriptArr); | 202 | body.Add("Script", scriptArr); |
194 | 203 | ||
195 | return BuildEvent("ScriptRunningReply", body); | 204 | return BuildEvent("ScriptRunningReply", body); |
196 | } | 205 | } |
197 | 206 | ||
@@ -204,8 +213,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
204 | {"sim-ip-and-port", new OSDString(simIpAndPort)}, | 213 | {"sim-ip-and-port", new OSDString(simIpAndPort)}, |
205 | {"seed-capability", new OSDString(seedcap)}, | 214 | {"seed-capability", new OSDString(seedcap)}, |
206 | {"region-handle", OSD.FromULong(regionHandle)}, | 215 | {"region-handle", OSD.FromULong(regionHandle)}, |
207 | {"region-size-x", OSD.FromInteger(regionSizeX)}, | 216 | {"region-size-x", OSD.FromUInteger((uint)regionSizeX)}, |
208 | {"region-size-y", OSD.FromInteger(regionSizeY)} | 217 | {"region-size-y", OSD.FromUInteger((uint)regionSizeY)} |
209 | }; | 218 | }; |
210 | 219 | ||
211 | return BuildEvent("EstablishAgentCommunication", body); | 220 | return BuildEvent("EstablishAgentCommunication", body); |
@@ -234,7 +243,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
234 | { | 243 | { |
235 | OSDMap messageParams = new OSDMap(15); | 244 | OSDMap messageParams = new OSDMap(15); |
236 | messageParams.Add("type", new OSDInteger((int)dialog)); | 245 | messageParams.Add("type", new OSDInteger((int)dialog)); |
237 | 246 | ||
238 | OSDArray positionArray = new OSDArray(3); | 247 | OSDArray positionArray = new OSDArray(3); |
239 | positionArray.Add(OSD.FromReal(position.X)); | 248 | positionArray.Add(OSD.FromReal(position.X)); |
240 | positionArray.Add(OSD.FromReal(position.Y)); | 249 | positionArray.Add(OSD.FromReal(position.Y)); |
@@ -299,20 +308,29 @@ namespace OpenSim.Region.ClientStack.Linden | |||
299 | } | 308 | } |
300 | 309 | ||
301 | public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID, | 310 | public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID, |
302 | UUID agentID, bool canVoiceChat, bool isModerator, bool textMute) | 311 | UUID agentID, bool canVoiceChat, bool isModerator, bool textMute, bool isEnterorLeave) |
303 | { | 312 | { |
304 | OSDMap body = new OSDMap(); | 313 | OSDMap body = new OSDMap(); |
305 | OSDMap agentUpdates = new OSDMap(); | 314 | OSDMap agentUpdates = new OSDMap(); |
306 | OSDMap infoDetail = new OSDMap(); | 315 | OSDMap infoDetail = new OSDMap(); |
307 | OSDMap mutes = new OSDMap(); | 316 | OSDMap mutes = new OSDMap(); |
308 | 317 | ||
318 | // this should be a list of agents and parameters | ||
319 | // foreach agent | ||
309 | mutes.Add("text", OSD.FromBoolean(textMute)); | 320 | mutes.Add("text", OSD.FromBoolean(textMute)); |
310 | infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat)); | 321 | infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat)); |
311 | infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator)); | 322 | infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator)); |
312 | infoDetail.Add("mutes", mutes); | 323 | infoDetail.Add("mutes", mutes); |
313 | OSDMap info = new OSDMap(); | 324 | OSDMap info = new OSDMap(); |
314 | info.Add("info", infoDetail); | 325 | info.Add("info", infoDetail); |
326 | if(isEnterorLeave) | ||
327 | info.Add("transition",OSD.FromString("ENTER")); | ||
328 | else | ||
329 | info.Add("transition",OSD.FromString("LEAVE")); | ||
315 | agentUpdates.Add(agentID.ToString(), info); | 330 | agentUpdates.Add(agentID.ToString(), info); |
331 | |||
332 | // foreach end | ||
333 | |||
316 | body.Add("agent_updates", agentUpdates); | 334 | body.Add("agent_updates", agentUpdates); |
317 | body.Add("session_id", OSD.FromUUID(sessionID)); | 335 | body.Add("session_id", OSD.FromUUID(sessionID)); |
318 | body.Add("updates", new OSD()); | 336 | body.Add("updates", new OSD()); |
@@ -324,40 +342,54 @@ namespace OpenSim.Region.ClientStack.Linden | |||
324 | return chatterBoxSessionAgentListUpdates; | 342 | return chatterBoxSessionAgentListUpdates; |
325 | } | 343 | } |
326 | 344 | ||
327 | public static OSD GroupMembership(AgentGroupDataUpdatePacket groupUpdatePacket) | 345 | public static OSD ChatterBoxForceClose(UUID sessionID, string reason) |
328 | { | 346 | { |
329 | OSDMap groupUpdate = new OSDMap(); | 347 | OSDMap body = new OSDMap(2); |
330 | groupUpdate.Add("message", OSD.FromString("AgentGroupDataUpdate")); | 348 | body.Add("session_id", new OSDUUID(sessionID)); |
349 | body.Add("reason", new OSDString(reason)); | ||
331 | 350 | ||
332 | OSDMap body = new OSDMap(); | 351 | OSDMap chatterBoxForceClose = new OSDMap(2); |
333 | OSDArray agentData = new OSDArray(); | 352 | chatterBoxForceClose.Add("message", new OSDString("ForceCloseChatterBoxSession")); |
334 | OSDMap agentDataMap = new OSDMap(); | 353 | chatterBoxForceClose.Add("body", body); |
335 | agentDataMap.Add("AgentID", OSD.FromUUID(groupUpdatePacket.AgentData.AgentID)); | 354 | return chatterBoxForceClose; |
336 | agentData.Add(agentDataMap); | 355 | } |
337 | body.Add("AgentData", agentData); | ||
338 | 356 | ||
339 | OSDArray groupData = new OSDArray(); | 357 | public static OSD GroupMembershipData(UUID receiverAgent, GroupMembershipData[] data) |
358 | { | ||
359 | OSDArray AgentData = new OSDArray(1); | ||
360 | OSDMap AgentDataMap = new OSDMap(1); | ||
361 | AgentDataMap.Add("AgentID", OSD.FromUUID(receiverAgent)); | ||
362 | AgentData.Add(AgentDataMap); | ||
340 | 363 | ||
341 | foreach (AgentGroupDataUpdatePacket.GroupDataBlock groupDataBlock in groupUpdatePacket.GroupData) | 364 | OSDArray GroupData = new OSDArray(data.Length); |
365 | OSDArray NewGroupData = new OSDArray(data.Length); | ||
366 | |||
367 | foreach (GroupMembershipData membership in data) | ||
342 | { | 368 | { |
343 | OSDMap groupDataMap = new OSDMap(); | 369 | OSDMap GroupDataMap = new OSDMap(6); |
344 | groupDataMap.Add("ListInProfile", OSD.FromBoolean(false)); | 370 | OSDMap NewGroupDataMap = new OSDMap(1); |
345 | groupDataMap.Add("GroupID", OSD.FromUUID(groupDataBlock.GroupID)); | 371 | |
346 | groupDataMap.Add("GroupInsigniaID", OSD.FromUUID(groupDataBlock.GroupInsigniaID)); | 372 | GroupDataMap.Add("GroupID", OSD.FromUUID(membership.GroupID)); |
347 | groupDataMap.Add("Contribution", OSD.FromInteger(groupDataBlock.Contribution)); | 373 | GroupDataMap.Add("GroupPowers", OSD.FromULong(membership.GroupPowers)); |
348 | groupDataMap.Add("GroupPowers", OSD.FromBinary(ulongToByteArray(groupDataBlock.GroupPowers))); | 374 | GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(membership.AcceptNotices)); |
349 | groupDataMap.Add("GroupName", OSD.FromString(Utils.BytesToString(groupDataBlock.GroupName))); | 375 | GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(membership.GroupPicture)); |
350 | groupDataMap.Add("AcceptNotices", OSD.FromBoolean(groupDataBlock.AcceptNotices)); | 376 | GroupDataMap.Add("Contribution", OSD.FromInteger(membership.Contribution)); |
377 | GroupDataMap.Add("GroupName", OSD.FromString(membership.GroupName)); | ||
378 | NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(membership.ListInProfile)); | ||
379 | |||
380 | GroupData.Add(GroupDataMap); | ||
381 | NewGroupData.Add(NewGroupDataMap); | ||
382 | } | ||
351 | 383 | ||
352 | groupData.Add(groupDataMap); | 384 | OSDMap llDataStruct = new OSDMap(3); |
385 | llDataStruct.Add("AgentData", AgentData); | ||
386 | llDataStruct.Add("GroupData", GroupData); | ||
387 | llDataStruct.Add("NewGroupData", NewGroupData); | ||
353 | 388 | ||
354 | } | 389 | return BuildEvent("AgentGroupDataUpdate", llDataStruct); |
355 | body.Add("GroupData", groupData); | ||
356 | groupUpdate.Add("body", body); | ||
357 | 390 | ||
358 | return groupUpdate; | ||
359 | } | 391 | } |
360 | 392 | ||
361 | public static OSD PlacesQuery(PlacesReplyPacket PlacesReply) | 393 | public static OSD PlacesQuery(PlacesReplyPacket PlacesReply) |
362 | { | 394 | { |
363 | OSDMap placesReply = new OSDMap(); | 395 | OSDMap placesReply = new OSDMap(); |
@@ -391,7 +423,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
391 | QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID)); | 423 | QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID)); |
392 | QueryDataMap.Add("ProductSku", OSD.FromInteger(0)); | 424 | QueryDataMap.Add("ProductSku", OSD.FromInteger(0)); |
393 | QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price)); | 425 | QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price)); |
394 | 426 | ||
395 | QueryData.Add(QueryDataMap); | 427 | QueryData.Add(QueryDataMap); |
396 | } | 428 | } |
397 | body.Add("QueryData", QueryData); | 429 | body.Add("QueryData", QueryData); |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index 16a902d..ee3f4f1 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs | |||
@@ -71,7 +71,6 @@ namespace OpenSim.Region.ClientStack.Linden.Tests | |||
71 | 71 | ||
72 | IConfigSource config = new IniConfigSource(); | 72 | IConfigSource config = new IniConfigSource(); |
73 | config.AddConfig("Startup"); | 73 | config.AddConfig("Startup"); |
74 | config.Configs["Startup"].Set("EventQueue", "true"); | ||
75 | 74 | ||
76 | CapabilitiesModule capsModule = new CapabilitiesModule(); | 75 | CapabilitiesModule capsModule = new CapabilitiesModule(); |
77 | m_eqgMod = new EventQueueGetModule(); | 76 | m_eqgMod = new EventQueueGetModule(); |
@@ -126,6 +125,15 @@ namespace OpenSim.Region.ClientStack.Linden.Tests | |||
126 | 125 | ||
127 | Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); | 126 | Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); |
128 | 127 | ||
128 | // initial queue as null events | ||
129 | eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); | ||
130 | if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK) | ||
131 | { | ||
132 | eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); | ||
133 | if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK) | ||
134 | eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); | ||
135 | } | ||
136 | |||
129 | Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK)); | 137 | Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK)); |
130 | 138 | ||
131 | // Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]); | 139 | // Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]); |
@@ -172,7 +180,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests | |||
172 | TestHelpers.InMethod(); | 180 | TestHelpers.InMethod(); |
173 | // TestHelpers.EnableLogging(); | 181 | // TestHelpers.EnableLogging(); |
174 | 182 | ||
175 | UUID npcId | 183 | UUID npcId |
176 | = m_npcMod.CreateNPC( | 184 | = m_npcMod.CreateNPC( |
177 | "John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance()); | 185 | "John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance()); |
178 | 186 | ||
@@ -187,4 +195,4 @@ namespace OpenSim.Region.ClientStack.Linden.Tests | |||
187 | Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway)); | 195 | Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway)); |
188 | } | 196 | } |
189 | } | 197 | } |
190 | } \ No newline at end of file | 198 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs deleted file mode 100644 index 6617bbc..0000000 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs +++ /dev/null | |||
@@ -1,144 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
33 | using System.Reflection; | ||
34 | using System.IO; | ||
35 | using System.Web; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using Mono.Addins; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenMetaverse.Imaging; | ||
42 | using OpenSim.Framework; | ||
43 | using OpenSim.Framework.Servers; | ||
44 | using OpenSim.Framework.Servers.HttpServer; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using OpenSim.Services.Interfaces; | ||
48 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
49 | using OpenSim.Capabilities.Handlers; | ||
50 | |||
51 | namespace OpenSim.Region.ClientStack.Linden | ||
52 | { | ||
53 | |||
54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetDisplayNamesModule")] | ||
55 | public class GetDisplayNamesModule : INonSharedRegionModule | ||
56 | { | ||
57 | private static readonly ILog m_log = | ||
58 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | |||
60 | private Scene m_scene; | ||
61 | private IUserManagement m_UserManager; | ||
62 | |||
63 | private bool m_Enabled = false; | ||
64 | |||
65 | private string m_URL; | ||
66 | |||
67 | #region ISharedRegionModule Members | ||
68 | |||
69 | public void Initialise(IConfigSource source) | ||
70 | { | ||
71 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
72 | if (config == null) | ||
73 | return; | ||
74 | |||
75 | m_URL = config.GetString("Cap_GetDisplayNames", string.Empty); | ||
76 | if (m_URL != string.Empty) | ||
77 | m_Enabled = true; | ||
78 | } | ||
79 | |||
80 | public void AddRegion(Scene s) | ||
81 | { | ||
82 | if (!m_Enabled) | ||
83 | return; | ||
84 | |||
85 | m_scene = s; | ||
86 | } | ||
87 | |||
88 | public void RemoveRegion(Scene s) | ||
89 | { | ||
90 | if (!m_Enabled) | ||
91 | return; | ||
92 | |||
93 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
94 | m_scene = null; | ||
95 | } | ||
96 | |||
97 | public void RegionLoaded(Scene s) | ||
98 | { | ||
99 | if (!m_Enabled) | ||
100 | return; | ||
101 | |||
102 | m_UserManager = m_scene.RequestModuleInterface<IUserManagement>(); | ||
103 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
104 | } | ||
105 | |||
106 | public void PostInitialise() | ||
107 | { | ||
108 | } | ||
109 | |||
110 | public void Close() { } | ||
111 | |||
112 | public string Name { get { return "GetDisplayNamesModule"; } } | ||
113 | |||
114 | public Type ReplaceableInterface | ||
115 | { | ||
116 | get { return null; } | ||
117 | } | ||
118 | |||
119 | #endregion | ||
120 | |||
121 | public void RegisterCaps(UUID agentID, Caps caps) | ||
122 | { | ||
123 | UUID capID = UUID.Random(); | ||
124 | |||
125 | if (m_URL == "localhost") | ||
126 | { | ||
127 | m_log.DebugFormat("[GET_DISPLAY_NAMES]: /CAPS/agents/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
128 | caps.RegisterHandler( | ||
129 | "GetDisplayNames", | ||
130 | new GetDisplayNamesHandler("/CAPS/agents" + capID + "/", m_UserManager, "GetDisplayNames", agentID.ToString())); | ||
131 | } | ||
132 | else | ||
133 | { | ||
134 | // m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | ||
135 | IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); | ||
136 | if (handler != null) | ||
137 | handler.RegisterExternalUserCapsHandler(agentID,caps,"GetDisplayNames", m_URL); | ||
138 | else | ||
139 | caps.RegisterHandler("GetDisplayNames", m_URL); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | } | ||
144 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs index f57d857..ba917e39 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs | |||
@@ -27,11 +27,14 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | 31 | using System.Collections.Specialized; |
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using System.IO; | 33 | using System.IO; |
34 | using System.Threading; | ||
33 | using System.Web; | 35 | using System.Web; |
34 | using Mono.Addins; | 36 | using Mono.Addins; |
37 | using OpenSim.Framework.Monitoring; | ||
35 | using log4net; | 38 | using log4net; |
36 | using Nini.Config; | 39 | using Nini.Config; |
37 | using OpenMetaverse; | 40 | using OpenMetaverse; |
@@ -52,15 +55,46 @@ namespace OpenSim.Region.ClientStack.Linden | |||
52 | { | 55 | { |
53 | // private static readonly ILog m_log = | 56 | // private static readonly ILog m_log = |
54 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 57 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
55 | 58 | ||
56 | private Scene m_scene; | 59 | private Scene m_scene; |
57 | private IAssetService m_AssetService; | 60 | private IAssetService m_AssetService; |
58 | private bool m_Enabled = true; | 61 | private bool m_Enabled = true; |
59 | private string m_URL; | 62 | private string m_URL; |
63 | |||
60 | private string m_URL2; | 64 | private string m_URL2; |
61 | private string m_RedirectURL = null; | 65 | private string m_RedirectURL = null; |
62 | private string m_RedirectURL2 = null; | 66 | private string m_RedirectURL2 = null; |
63 | 67 | ||
68 | struct aPollRequest | ||
69 | { | ||
70 | public PollServiceMeshEventArgs thepoll; | ||
71 | public UUID reqID; | ||
72 | public Hashtable request; | ||
73 | } | ||
74 | |||
75 | public class aPollResponse | ||
76 | { | ||
77 | public Hashtable response; | ||
78 | public int bytes; | ||
79 | public int lod; | ||
80 | } | ||
81 | |||
82 | |||
83 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
84 | |||
85 | private static GetMeshHandler m_getMeshHandler; | ||
86 | |||
87 | private IAssetService m_assetService = null; | ||
88 | |||
89 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); | ||
90 | private static Thread[] m_workerThreads = null; | ||
91 | private static int m_NumberScenes = 0; | ||
92 | private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue = | ||
93 | new OpenSim.Framework.BlockingQueue<aPollRequest>(); | ||
94 | |||
95 | private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>(); | ||
96 | |||
97 | |||
64 | #region Region Module interfaceBase Members | 98 | #region Region Module interfaceBase Members |
65 | 99 | ||
66 | public Type ReplaceableInterface | 100 | public Type ReplaceableInterface |
@@ -87,6 +121,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
87 | if (m_URL2 != string.Empty) | 121 | if (m_URL2 != string.Empty) |
88 | { | 122 | { |
89 | m_Enabled = true; | 123 | m_Enabled = true; |
124 | |||
90 | m_RedirectURL2 = config.GetString("GetMesh2RedirectURL"); | 125 | m_RedirectURL2 = config.GetString("GetMesh2RedirectURL"); |
91 | } | 126 | } |
92 | } | 127 | } |
@@ -97,6 +132,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
97 | return; | 132 | return; |
98 | 133 | ||
99 | m_scene = pScene; | 134 | m_scene = pScene; |
135 | |||
136 | m_assetService = pScene.AssetService; | ||
100 | } | 137 | } |
101 | 138 | ||
102 | public void RemoveRegion(Scene scene) | 139 | public void RemoveRegion(Scene scene) |
@@ -105,6 +142,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
105 | return; | 142 | return; |
106 | 143 | ||
107 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | 144 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; |
145 | m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; | ||
146 | m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate; | ||
147 | m_NumberScenes--; | ||
108 | m_scene = null; | 148 | m_scene = null; |
109 | } | 149 | } |
110 | 150 | ||
@@ -115,55 +155,302 @@ namespace OpenSim.Region.ClientStack.Linden | |||
115 | 155 | ||
116 | m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); | 156 | m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); |
117 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | 157 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; |
118 | } | 158 | // We'll reuse the same handler for all requests. |
159 | m_getMeshHandler = new GetMeshHandler(m_assetService); | ||
160 | m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; | ||
161 | m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate; | ||
119 | 162 | ||
163 | m_NumberScenes++; | ||
164 | |||
165 | if (m_workerThreads == null) | ||
166 | { | ||
167 | m_workerThreads = new Thread[2]; | ||
168 | |||
169 | for (uint i = 0; i < 2; i++) | ||
170 | { | ||
171 | m_workerThreads[i] = WorkManager.StartThread(DoMeshRequests, | ||
172 | String.Format("GetMeshWorker{0}", i), | ||
173 | ThreadPriority.Normal, | ||
174 | true, | ||
175 | false, | ||
176 | null, | ||
177 | int.MaxValue); | ||
178 | } | ||
179 | } | ||
180 | } | ||
120 | 181 | ||
121 | public void Close() { } | 182 | public void Close() |
183 | { | ||
184 | if(m_NumberScenes <= 0 && m_workerThreads != null) | ||
185 | { | ||
186 | m_log.DebugFormat("[GetMeshModule] Closing"); | ||
187 | foreach (Thread t in m_workerThreads) | ||
188 | Watchdog.AbortThread(t.ManagedThreadId); | ||
189 | // This will fail on region shutdown. Its harmless. | ||
190 | // Prevent red ink. | ||
191 | try | ||
192 | { | ||
193 | m_queue.Clear(); | ||
194 | } | ||
195 | catch {} | ||
196 | } | ||
197 | } | ||
122 | 198 | ||
123 | public string Name { get { return "GetMeshModule"; } } | 199 | public string Name { get { return "GetMeshModule"; } } |
124 | 200 | ||
125 | #endregion | 201 | #endregion |
126 | 202 | ||
203 | private static void DoMeshRequests() | ||
204 | { | ||
205 | while(true) | ||
206 | { | ||
207 | aPollRequest poolreq = m_queue.Dequeue(4500); | ||
208 | Watchdog.UpdateThread(); | ||
209 | if(m_NumberScenes <= 0) | ||
210 | return; | ||
211 | if(poolreq.reqID != UUID.Zero) | ||
212 | poolreq.thepoll.Process(poolreq); | ||
213 | } | ||
214 | } | ||
127 | 215 | ||
128 | public void RegisterCaps(UUID agentID, Caps caps) | 216 | // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent. |
217 | public void ThrottleUpdate(ScenePresence p) | ||
129 | { | 218 | { |
130 | UUID capID = UUID.Random(); | 219 | UUID user = p.UUID; |
131 | bool getMeshRegistered = false; | 220 | int imagethrottle = p.ControllingClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset); |
221 | PollServiceMeshEventArgs args; | ||
222 | if (m_pollservices.TryGetValue(user, out args)) | ||
223 | { | ||
224 | args.UpdateThrottle(imagethrottle); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | private class PollServiceMeshEventArgs : PollServiceEventArgs | ||
229 | { | ||
230 | private List<Hashtable> requests = | ||
231 | new List<Hashtable>(); | ||
232 | private Dictionary<UUID, aPollResponse> responses = | ||
233 | new Dictionary<UUID, aPollResponse>(); | ||
234 | |||
235 | private Scene m_scene; | ||
236 | private MeshCapsDataThrottler m_throttler; | ||
237 | public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) : | ||
238 | base(null, uri, null, null, null, pId, int.MaxValue) | ||
239 | { | ||
240 | m_scene = scene; | ||
241 | m_throttler = new MeshCapsDataThrottler(100000); | ||
242 | // x is request id, y is userid | ||
243 | HasEvents = (x, y) => | ||
244 | { | ||
245 | lock (responses) | ||
246 | { | ||
247 | bool ret = m_throttler.hasEvents(x, responses); | ||
248 | return ret; | ||
249 | |||
250 | } | ||
251 | }; | ||
252 | GetEvents = (x, y) => | ||
253 | { | ||
254 | lock (responses) | ||
255 | { | ||
256 | try | ||
257 | { | ||
258 | return responses[x].response; | ||
259 | } | ||
260 | finally | ||
261 | { | ||
262 | responses.Remove(x); | ||
263 | m_throttler.PassTime(); | ||
264 | } | ||
265 | } | ||
266 | }; | ||
267 | // x is request id, y is request data hashtable | ||
268 | Request = (x, y) => | ||
269 | { | ||
270 | aPollRequest reqinfo = new aPollRequest(); | ||
271 | reqinfo.thepoll = this; | ||
272 | reqinfo.reqID = x; | ||
273 | reqinfo.request = y; | ||
274 | |||
275 | m_queue.Enqueue(reqinfo); | ||
276 | m_throttler.PassTime(); | ||
277 | }; | ||
132 | 278 | ||
133 | if (m_URL == string.Empty) | 279 | // this should never happen except possible on shutdown |
280 | NoEvents = (x, y) => | ||
281 | { | ||
282 | /* | ||
283 | lock (requests) | ||
284 | { | ||
285 | Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString()); | ||
286 | requests.Remove(request); | ||
287 | } | ||
288 | */ | ||
289 | Hashtable response = new Hashtable(); | ||
290 | |||
291 | response["int_response_code"] = 500; | ||
292 | response["str_response_string"] = "Script timeout"; | ||
293 | response["content_type"] = "text/plain"; | ||
294 | response["keepalive"] = false; | ||
295 | response["reusecontext"] = false; | ||
296 | |||
297 | return response; | ||
298 | }; | ||
299 | } | ||
300 | |||
301 | public void Process(aPollRequest requestinfo) | ||
134 | { | 302 | { |
303 | Hashtable response; | ||
304 | |||
305 | UUID requestID = requestinfo.reqID; | ||
306 | |||
307 | if(m_scene.ShuttingDown) | ||
308 | return; | ||
309 | |||
310 | // If the avatar is gone, don't bother to get the texture | ||
311 | if (m_scene.GetScenePresence(Id) == null) | ||
312 | { | ||
313 | response = new Hashtable(); | ||
314 | |||
315 | response["int_response_code"] = 500; | ||
316 | response["str_response_string"] = "Script timeout"; | ||
317 | response["content_type"] = "text/plain"; | ||
318 | response["keepalive"] = false; | ||
319 | response["reusecontext"] = false; | ||
320 | |||
321 | lock (responses) | ||
322 | responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 }; | ||
323 | |||
324 | return; | ||
325 | } | ||
326 | |||
327 | response = m_getMeshHandler.Handle(requestinfo.request); | ||
328 | lock (responses) | ||
329 | { | ||
330 | responses[requestID] = new aPollResponse() | ||
331 | { | ||
332 | bytes = (int)response["int_bytes"], | ||
333 | lod = (int)response["int_lod"], | ||
334 | response = response | ||
335 | }; | ||
336 | |||
337 | } | ||
338 | m_throttler.PassTime(); | ||
339 | } | ||
135 | 340 | ||
341 | internal void UpdateThrottle(int pthrottle) | ||
342 | { | ||
343 | int tmp = 2 * pthrottle; | ||
344 | if(tmp < 10000) | ||
345 | tmp = 10000; | ||
346 | m_throttler.ThrottleBytes = tmp; | ||
136 | } | 347 | } |
137 | else if (m_URL == "localhost") | 348 | } |
349 | |||
350 | public void RegisterCaps(UUID agentID, Caps caps) | ||
351 | { | ||
352 | // UUID capID = UUID.Random(); | ||
353 | if (m_URL == "localhost") | ||
138 | { | 354 | { |
139 | getMeshRegistered = true; | 355 | string capUrl = "/CAPS/" + UUID.Random() + "/"; |
140 | caps.RegisterHandler( | 356 | |
141 | "GetMesh", | 357 | // Register this as a poll service |
142 | new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh", agentID.ToString(), m_RedirectURL)); | 358 | PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene); |
359 | |||
360 | args.Type = PollServiceEventArgs.EventType.Mesh; | ||
361 | MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); | ||
362 | |||
363 | string hostName = m_scene.RegionInfo.ExternalHostName; | ||
364 | uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; | ||
365 | string protocol = "http"; | ||
366 | |||
367 | if (MainServer.Instance.UseSSL) | ||
368 | { | ||
369 | hostName = MainServer.Instance.SSLCommonName; | ||
370 | port = MainServer.Instance.SSLPort; | ||
371 | protocol = "https"; | ||
372 | } | ||
373 | caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); | ||
374 | m_pollservices[agentID] = args; | ||
375 | m_capsDict[agentID] = capUrl; | ||
143 | } | 376 | } |
144 | else | 377 | else |
145 | { | 378 | { |
146 | caps.RegisterHandler("GetMesh", m_URL); | 379 | caps.RegisterHandler("GetMesh", m_URL); |
147 | } | 380 | } |
381 | } | ||
148 | 382 | ||
149 | if(m_URL2 == string.Empty) | 383 | private void DeregisterCaps(UUID agentID, Caps caps) |
384 | { | ||
385 | string capUrl; | ||
386 | PollServiceMeshEventArgs args; | ||
387 | if (m_capsDict.TryGetValue(agentID, out capUrl)) | ||
388 | { | ||
389 | MainServer.Instance.RemoveHTTPHandler("", capUrl); | ||
390 | m_capsDict.Remove(agentID); | ||
391 | } | ||
392 | if (m_pollservices.TryGetValue(agentID, out args)) | ||
150 | { | 393 | { |
394 | m_pollservices.Remove(agentID); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | internal sealed class MeshCapsDataThrottler | ||
399 | { | ||
400 | private double lastTimeElapsed = 0; | ||
401 | private double BytesSent = 0; | ||
151 | 402 | ||
403 | public MeshCapsDataThrottler(int pBytes) | ||
404 | { | ||
405 | if(pBytes < 10000) | ||
406 | pBytes = 10000; | ||
407 | ThrottleBytes = pBytes; | ||
408 | lastTimeElapsed = Util.GetTimeStampMS(); | ||
152 | } | 409 | } |
153 | else if (m_URL2 == "localhost") | 410 | |
411 | public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses) | ||
154 | { | 412 | { |
155 | if (!getMeshRegistered) | 413 | PassTime(); |
414 | // Note, this is called IN LOCK | ||
415 | bool haskey = responses.ContainsKey(key); | ||
416 | |||
417 | if (!haskey) | ||
418 | { | ||
419 | return false; | ||
420 | } | ||
421 | aPollResponse response; | ||
422 | if (responses.TryGetValue(key, out response)) | ||
156 | { | 423 | { |
157 | caps.RegisterHandler( | 424 | // Normal |
158 | "GetMesh2", | 425 | if (BytesSent <= ThrottleBytes) |
159 | new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh2", agentID.ToString(), m_RedirectURL2)); | 426 | { |
427 | BytesSent += response.bytes; | ||
428 | return true; | ||
429 | } | ||
430 | else | ||
431 | { | ||
432 | return false; | ||
433 | } | ||
160 | } | 434 | } |
435 | return haskey; | ||
161 | } | 436 | } |
162 | else | 437 | |
438 | public void PassTime() | ||
163 | { | 439 | { |
164 | caps.RegisterHandler("GetMesh2", m_URL2); | 440 | double currenttime = Util.GetTimeStampMS(); |
441 | double timeElapsed = currenttime - lastTimeElapsed; | ||
442 | if(timeElapsed < 50.0) | ||
443 | return; | ||
444 | int add = (int)(ThrottleBytes * timeElapsed * 0.001); | ||
445 | if (add >= 1000) | ||
446 | { | ||
447 | lastTimeElapsed = currenttime; | ||
448 | BytesSent -= add; | ||
449 | if (BytesSent < 0) BytesSent = 0; | ||
450 | } | ||
165 | } | 451 | } |
166 | } | ||
167 | 452 | ||
453 | public int ThrottleBytes; | ||
454 | } | ||
168 | } | 455 | } |
169 | } | 456 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index bb932f2..b01c7dc 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | |||
@@ -27,18 +27,13 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Specialized; | 30 | using System.Collections.Generic; |
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
33 | using System.Reflection; | 31 | using System.Reflection; |
34 | using System.IO; | 32 | using System.Threading; |
35 | using System.Web; | ||
36 | using log4net; | 33 | using log4net; |
37 | using Nini.Config; | 34 | using Nini.Config; |
38 | using Mono.Addins; | 35 | using Mono.Addins; |
39 | using OpenMetaverse; | 36 | using OpenMetaverse; |
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenMetaverse.Imaging; | ||
42 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
43 | using OpenSim.Framework.Servers; | 38 | using OpenSim.Framework.Servers; |
44 | using OpenSim.Framework.Servers.HttpServer; | 39 | using OpenSim.Framework.Servers.HttpServer; |
@@ -47,6 +42,7 @@ using OpenSim.Region.Framework.Scenes; | |||
47 | using OpenSim.Services.Interfaces; | 42 | using OpenSim.Services.Interfaces; |
48 | using Caps = OpenSim.Framework.Capabilities.Caps; | 43 | using Caps = OpenSim.Framework.Capabilities.Caps; |
49 | using OpenSim.Capabilities.Handlers; | 44 | using OpenSim.Capabilities.Handlers; |
45 | using OpenSim.Framework.Monitoring; | ||
50 | 46 | ||
51 | namespace OpenSim.Region.ClientStack.Linden | 47 | namespace OpenSim.Region.ClientStack.Linden |
52 | { | 48 | { |
@@ -54,27 +50,49 @@ namespace OpenSim.Region.ClientStack.Linden | |||
54 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] | 50 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] |
55 | public class GetTextureModule : INonSharedRegionModule | 51 | public class GetTextureModule : INonSharedRegionModule |
56 | { | 52 | { |
57 | // private static readonly ILog m_log = | 53 | |
58 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 54 | struct aPollRequest |
59 | 55 | { | |
56 | public PollServiceTextureEventArgs thepoll; | ||
57 | public UUID reqID; | ||
58 | public Hashtable request; | ||
59 | public bool send503; | ||
60 | } | ||
61 | |||
62 | public class aPollResponse | ||
63 | { | ||
64 | public Hashtable response; | ||
65 | public int bytes; | ||
66 | } | ||
67 | |||
68 | |||
69 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
70 | |||
60 | private Scene m_scene; | 71 | private Scene m_scene; |
61 | private IAssetService m_assetService; | ||
62 | 72 | ||
63 | private bool m_Enabled = false; | 73 | private static GetTextureHandler m_getTextureHandler; |
74 | |||
75 | private IAssetService m_assetService = null; | ||
76 | |||
77 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); | ||
78 | private static Thread[] m_workerThreads = null; | ||
79 | private static int m_NumberScenes = 0; | ||
80 | private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue = | ||
81 | new OpenSim.Framework.BlockingQueue<aPollRequest>(); | ||
64 | 82 | ||
65 | // TODO: Change this to a config option | 83 | private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); |
66 | private string m_RedirectURL = null; | ||
67 | 84 | ||
68 | private string m_URL; | 85 | private string m_Url = "localhost"; |
69 | 86 | ||
70 | #region ISharedRegionModule Members | 87 | #region ISharedRegionModule Members |
71 | 88 | ||
72 | public void Initialise(IConfigSource source) | 89 | public void Initialise(IConfigSource source) |
73 | { | 90 | { |
74 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | 91 | IConfig config = source.Configs["ClientStack.LindenCaps"]; |
92 | |||
75 | if (config == null) | 93 | if (config == null) |
76 | return; | 94 | return; |
77 | 95 | /* | |
78 | m_URL = config.GetString("Cap_GetTexture", string.Empty); | 96 | m_URL = config.GetString("Cap_GetTexture", string.Empty); |
79 | // Cap doesn't exist | 97 | // Cap doesn't exist |
80 | if (m_URL != string.Empty) | 98 | if (m_URL != string.Empty) |
@@ -82,39 +100,108 @@ namespace OpenSim.Region.ClientStack.Linden | |||
82 | m_Enabled = true; | 100 | m_Enabled = true; |
83 | m_RedirectURL = config.GetString("GetTextureRedirectURL"); | 101 | m_RedirectURL = config.GetString("GetTextureRedirectURL"); |
84 | } | 102 | } |
103 | */ | ||
104 | m_Url = config.GetString("Cap_GetTexture", "localhost"); | ||
85 | } | 105 | } |
86 | 106 | ||
87 | public void AddRegion(Scene s) | 107 | public void AddRegion(Scene s) |
88 | { | 108 | { |
89 | if (!m_Enabled) | ||
90 | return; | ||
91 | |||
92 | m_scene = s; | 109 | m_scene = s; |
110 | m_assetService = s.AssetService; | ||
93 | } | 111 | } |
94 | 112 | ||
95 | public void RemoveRegion(Scene s) | 113 | public void RemoveRegion(Scene s) |
96 | { | 114 | { |
97 | if (!m_Enabled) | ||
98 | return; | ||
99 | |||
100 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | 115 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; |
116 | m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; | ||
117 | m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate; | ||
118 | m_NumberScenes--; | ||
101 | m_scene = null; | 119 | m_scene = null; |
102 | } | 120 | } |
103 | 121 | ||
104 | public void RegionLoaded(Scene s) | 122 | public void RegionLoaded(Scene s) |
105 | { | 123 | { |
106 | if (!m_Enabled) | 124 | // We'll reuse the same handler for all requests. |
107 | return; | 125 | m_getTextureHandler = new GetTextureHandler(m_assetService); |
108 | 126 | ||
109 | m_assetService = m_scene.RequestModuleInterface<IAssetService>(); | ||
110 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | 127 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; |
128 | m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; | ||
129 | m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate; | ||
130 | |||
131 | m_NumberScenes++; | ||
132 | |||
133 | if (m_workerThreads == null) | ||
134 | { | ||
135 | m_workerThreads = new Thread[2]; | ||
136 | |||
137 | for (uint i = 0; i < 2; i++) | ||
138 | { | ||
139 | m_workerThreads[i] = WorkManager.StartThread(DoTextureRequests, | ||
140 | String.Format("GetTextureWorker{0}", i), | ||
141 | ThreadPriority.Normal, | ||
142 | true, | ||
143 | false, | ||
144 | null, | ||
145 | int.MaxValue); | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | private int ExtractImageThrottle(byte[] pthrottles) | ||
150 | { | ||
151 | |||
152 | byte[] adjData; | ||
153 | int pos = 0; | ||
154 | |||
155 | if (!BitConverter.IsLittleEndian) | ||
156 | { | ||
157 | byte[] newData = new byte[7 * 4]; | ||
158 | Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4); | ||
159 | |||
160 | for (int i = 0; i < 7; i++) | ||
161 | Array.Reverse(newData, i * 4, 4); | ||
162 | |||
163 | adjData = newData; | ||
164 | } | ||
165 | else | ||
166 | { | ||
167 | adjData = pthrottles; | ||
168 | } | ||
169 | |||
170 | pos = pos + 20; | ||
171 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4; | ||
172 | //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
173 | return texture; | ||
174 | } | ||
175 | |||
176 | // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent. | ||
177 | public void ThrottleUpdate(ScenePresence p) | ||
178 | { | ||
179 | byte[] throttles = p.ControllingClient.GetThrottlesPacked(1); | ||
180 | UUID user = p.UUID; | ||
181 | int imagethrottle = ExtractImageThrottle(throttles); | ||
182 | PollServiceTextureEventArgs args; | ||
183 | if (m_pollservices.TryGetValue(user,out args)) | ||
184 | { | ||
185 | args.UpdateThrottle(imagethrottle); | ||
186 | } | ||
111 | } | 187 | } |
112 | 188 | ||
113 | public void PostInitialise() | 189 | public void PostInitialise() |
114 | { | 190 | { |
115 | } | 191 | } |
116 | 192 | ||
117 | public void Close() { } | 193 | public void Close() |
194 | { | ||
195 | if(m_NumberScenes <= 0 && m_workerThreads != null) | ||
196 | { | ||
197 | m_log.DebugFormat("[GetTextureModule] Closing"); | ||
198 | |||
199 | foreach (Thread t in m_workerThreads) | ||
200 | Watchdog.AbortThread(t.ManagedThreadId); | ||
201 | |||
202 | m_queue.Clear(); | ||
203 | } | ||
204 | } | ||
118 | 205 | ||
119 | public string Name { get { return "GetTextureModule"; } } | 206 | public string Name { get { return "GetTextureModule"; } } |
120 | 207 | ||
@@ -125,28 +212,277 @@ namespace OpenSim.Region.ClientStack.Linden | |||
125 | 212 | ||
126 | #endregion | 213 | #endregion |
127 | 214 | ||
128 | public void RegisterCaps(UUID agentID, Caps caps) | 215 | private class PollServiceTextureEventArgs : PollServiceEventArgs |
129 | { | 216 | { |
130 | UUID capID = UUID.Random(); | 217 | private List<Hashtable> requests = |
218 | new List<Hashtable>(); | ||
219 | private Dictionary<UUID, aPollResponse> responses = | ||
220 | new Dictionary<UUID, aPollResponse>(); | ||
221 | |||
222 | private Scene m_scene; | ||
223 | private CapsDataThrottler m_throttler = new CapsDataThrottler(100000); | ||
224 | public PollServiceTextureEventArgs(UUID pId, Scene scene) : | ||
225 | base(null, "", null, null, null, pId, int.MaxValue) | ||
226 | { | ||
227 | m_scene = scene; | ||
228 | // x is request id, y is userid | ||
229 | HasEvents = (x, y) => | ||
230 | { | ||
231 | lock (responses) | ||
232 | { | ||
233 | bool ret = m_throttler.hasEvents(x, responses); | ||
234 | return ret; | ||
235 | |||
236 | } | ||
237 | }; | ||
238 | GetEvents = (x, y) => | ||
239 | { | ||
240 | lock (responses) | ||
241 | { | ||
242 | try | ||
243 | { | ||
244 | return responses[x].response; | ||
245 | } | ||
246 | finally | ||
247 | { | ||
248 | responses.Remove(x); | ||
249 | m_throttler.PassTime(); | ||
250 | } | ||
251 | } | ||
252 | }; | ||
253 | // x is request id, y is request data hashtable | ||
254 | Request = (x, y) => | ||
255 | { | ||
256 | aPollRequest reqinfo = new aPollRequest(); | ||
257 | reqinfo.thepoll = this; | ||
258 | reqinfo.reqID = x; | ||
259 | reqinfo.request = y; | ||
260 | reqinfo.send503 = false; | ||
261 | |||
262 | lock (responses) | ||
263 | { | ||
264 | if (responses.Count > 0) | ||
265 | { | ||
266 | if (m_queue.Count() >= 4) | ||
267 | { | ||
268 | // Never allow more than 4 fetches to wait | ||
269 | reqinfo.send503 = true; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | m_queue.Enqueue(reqinfo); | ||
274 | m_throttler.PassTime(); | ||
275 | }; | ||
276 | |||
277 | // this should never happen except possible on shutdown | ||
278 | NoEvents = (x, y) => | ||
279 | { | ||
280 | /* | ||
281 | lock (requests) | ||
282 | { | ||
283 | Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString()); | ||
284 | requests.Remove(request); | ||
285 | } | ||
286 | */ | ||
287 | Hashtable response = new Hashtable(); | ||
131 | 288 | ||
132 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); | 289 | response["int_response_code"] = 500; |
133 | if (m_URL == "localhost") | 290 | response["str_response_string"] = "Script timeout"; |
291 | response["content_type"] = "text/plain"; | ||
292 | response["keepalive"] = false; | ||
293 | response["reusecontext"] = false; | ||
294 | |||
295 | return response; | ||
296 | }; | ||
297 | } | ||
298 | |||
299 | public void Process(aPollRequest requestinfo) | ||
134 | { | 300 | { |
135 | // m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | 301 | Hashtable response; |
136 | caps.RegisterHandler( | 302 | |
137 | "GetTexture", | 303 | UUID requestID = requestinfo.reqID; |
138 | new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString(), m_RedirectURL)); | 304 | |
305 | if(m_scene.ShuttingDown) | ||
306 | return; | ||
307 | |||
308 | if (requestinfo.send503) | ||
309 | { | ||
310 | response = new Hashtable(); | ||
311 | |||
312 | response["int_response_code"] = 503; | ||
313 | response["str_response_string"] = "Throttled"; | ||
314 | response["content_type"] = "text/plain"; | ||
315 | response["keepalive"] = false; | ||
316 | response["reusecontext"] = false; | ||
317 | |||
318 | Hashtable headers = new Hashtable(); | ||
319 | headers["Retry-After"] = 30; | ||
320 | response["headers"] = headers; | ||
321 | |||
322 | lock (responses) | ||
323 | responses[requestID] = new aPollResponse() {bytes = 0, response = response}; | ||
324 | |||
325 | return; | ||
326 | } | ||
327 | |||
328 | // If the avatar is gone, don't bother to get the texture | ||
329 | if (m_scene.GetScenePresence(Id) == null) | ||
330 | { | ||
331 | response = new Hashtable(); | ||
332 | |||
333 | response["int_response_code"] = 500; | ||
334 | response["str_response_string"] = "Script timeout"; | ||
335 | response["content_type"] = "text/plain"; | ||
336 | response["keepalive"] = false; | ||
337 | response["reusecontext"] = false; | ||
338 | |||
339 | lock (responses) | ||
340 | responses[requestID] = new aPollResponse() {bytes = 0, response = response}; | ||
341 | |||
342 | return; | ||
343 | } | ||
344 | |||
345 | response = m_getTextureHandler.Handle(requestinfo.request); | ||
346 | lock (responses) | ||
347 | { | ||
348 | responses[requestID] = new aPollResponse() | ||
349 | { | ||
350 | bytes = (int) response["int_bytes"], | ||
351 | response = response | ||
352 | }; | ||
353 | |||
354 | } | ||
355 | m_throttler.PassTime(); | ||
139 | } | 356 | } |
140 | else | 357 | |
358 | internal void UpdateThrottle(int pimagethrottle) | ||
141 | { | 359 | { |
142 | // m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | 360 | int tmp = 2 * pimagethrottle; |
361 | if(tmp < 10000) | ||
362 | tmp = 10000; | ||
363 | m_throttler.ThrottleBytes = tmp; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | private void RegisterCaps(UUID agentID, Caps caps) | ||
368 | { | ||
369 | if (m_Url == "localhost") | ||
370 | { | ||
371 | string capUrl = "/CAPS/" + UUID.Random() + "/"; | ||
372 | |||
373 | // Register this as a poll service | ||
374 | PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene); | ||
375 | |||
376 | args.Type = PollServiceEventArgs.EventType.Texture; | ||
377 | MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); | ||
378 | |||
379 | string hostName = m_scene.RegionInfo.ExternalHostName; | ||
380 | uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; | ||
381 | string protocol = "http"; | ||
382 | |||
383 | if (MainServer.Instance.UseSSL) | ||
384 | { | ||
385 | hostName = MainServer.Instance.SSLCommonName; | ||
386 | port = MainServer.Instance.SSLPort; | ||
387 | protocol = "https"; | ||
388 | } | ||
143 | IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); | 389 | IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); |
144 | if (handler != null) | 390 | if (handler != null) |
145 | handler.RegisterExternalUserCapsHandler(agentID,caps,"GetTexture", m_URL); | 391 | handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl); |
146 | else | 392 | else |
147 | caps.RegisterHandler("GetTexture", m_URL); | 393 | caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); |
394 | m_pollservices[agentID] = args; | ||
395 | m_capsDict[agentID] = capUrl; | ||
396 | } | ||
397 | else | ||
398 | { | ||
399 | caps.RegisterHandler("GetTexture", m_Url); | ||
400 | } | ||
401 | } | ||
402 | |||
403 | private void DeregisterCaps(UUID agentID, Caps caps) | ||
404 | { | ||
405 | PollServiceTextureEventArgs args; | ||
406 | |||
407 | MainServer.Instance.RemoveHTTPHandler("", m_Url); | ||
408 | m_capsDict.Remove(agentID); | ||
409 | |||
410 | if (m_pollservices.TryGetValue(agentID, out args)) | ||
411 | { | ||
412 | m_pollservices.Remove(agentID); | ||
413 | } | ||
414 | } | ||
415 | |||
416 | private static void DoTextureRequests() | ||
417 | { | ||
418 | while (true) | ||
419 | { | ||
420 | aPollRequest poolreq = m_queue.Dequeue(4500); | ||
421 | Watchdog.UpdateThread(); | ||
422 | if(m_NumberScenes <= 0) | ||
423 | return; | ||
424 | if(poolreq.reqID != UUID.Zero) | ||
425 | poolreq.thepoll.Process(poolreq); | ||
148 | } | 426 | } |
149 | } | 427 | } |
150 | 428 | ||
429 | internal sealed class CapsDataThrottler | ||
430 | { | ||
431 | private double lastTimeElapsed = 0; | ||
432 | private volatile int BytesSent = 0; | ||
433 | public CapsDataThrottler(int pBytes) | ||
434 | { | ||
435 | if(pBytes < 10000) | ||
436 | pBytes = 10000; | ||
437 | ThrottleBytes = pBytes; | ||
438 | lastTimeElapsed = Util.GetTimeStampMS(); | ||
439 | } | ||
440 | public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses) | ||
441 | { | ||
442 | PassTime(); | ||
443 | // Note, this is called IN LOCK | ||
444 | bool haskey = responses.ContainsKey(key); | ||
445 | if (!haskey) | ||
446 | { | ||
447 | return false; | ||
448 | } | ||
449 | GetTextureModule.aPollResponse response; | ||
450 | if (responses.TryGetValue(key, out response)) | ||
451 | { | ||
452 | // This is any error response | ||
453 | if (response.bytes == 0) | ||
454 | return true; | ||
455 | |||
456 | // Normal | ||
457 | if (BytesSent <= ThrottleBytes) | ||
458 | { | ||
459 | BytesSent += response.bytes; | ||
460 | return true; | ||
461 | } | ||
462 | else | ||
463 | { | ||
464 | return false; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | return haskey; | ||
469 | } | ||
470 | |||
471 | public void PassTime() | ||
472 | { | ||
473 | double currenttime = Util.GetTimeStampMS(); | ||
474 | double timeElapsed = currenttime - lastTimeElapsed; | ||
475 | if(timeElapsed < 50.0) | ||
476 | return; | ||
477 | int add = (int)(ThrottleBytes * timeElapsed * 0.001); | ||
478 | if (add >= 1000) | ||
479 | { | ||
480 | lastTimeElapsed = currenttime; | ||
481 | BytesSent -= add; | ||
482 | if (BytesSent < 0) BytesSent = 0; | ||
483 | } | ||
484 | } | ||
485 | public int ThrottleBytes; | ||
486 | } | ||
151 | } | 487 | } |
152 | } | 488 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs index 45d33cd..44bf1a5 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs | |||
@@ -129,23 +129,23 @@ namespace OpenSim.Region.ClientStack.Linden | |||
129 | // m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); | 129 | // m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); |
130 | 130 | ||
131 | OSDMap data = new OSDMap(); | 131 | OSDMap data = new OSDMap(); |
132 | ScenePresence sp = m_scene.GetScenePresence(agentID); | 132 | // ScenePresence sp = m_scene.GetScenePresence(m_agentID); |
133 | data["username"] = sp.Firstname + "." + sp.Lastname; | 133 | // data["username"] = sp.Firstname + "." + sp.Lastname; |
134 | data["display_name_next_update"] = new OSDDate(DateTime.Now); | 134 | // data["display_name_next_update"] = new OSDDate(DateTime.Now); |
135 | data["legacy_first_name"] = sp.Firstname; | 135 | // data["legacy_first_name"] = sp.Firstname; |
136 | data["mesh_upload_status"] = "valid"; | 136 | data["mesh_upload_status"] = "valid"; |
137 | data["display_name"] = sp.Firstname + " " + sp.Lastname; | 137 | // data["display_name"] = sp.Firstname + " " + sp.Lastname; |
138 | data["legacy_last_name"] = sp.Lastname; | 138 | // data["legacy_last_name"] = sp.Lastname; |
139 | data["id"] = agentID; | 139 | // data["id"] = m_agentID; |
140 | data["is_display_name_default"] = true; | 140 | // data["is_display_name_default"] = true; |
141 | 141 | ||
142 | //Send back data | 142 | //Send back data |
143 | Hashtable responsedata = new Hashtable(); | 143 | Hashtable responsedata = new Hashtable(); |
144 | responsedata["int_response_code"] = 200; | 144 | responsedata["int_response_code"] = 200; |
145 | responsedata["content_type"] = "text/plain"; | 145 | responsedata["content_type"] = "text/plain"; |
146 | responsedata["keepalive"] = false; | 146 | responsedata["keepalive"] = false; |
147 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(data); | 147 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(data); |
148 | return responsedata; | 148 | return responsedata; |
149 | } | 149 | } |
150 | } | 150 | } |
151 | } \ No newline at end of file | 151 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs deleted file mode 100644 index f69a0bb..0000000 --- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs +++ /dev/null | |||
@@ -1,297 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using System.IO; | ||
33 | using System.Web; | ||
34 | using Mono.Addins; | ||
35 | using log4net; | ||
36 | using Nini.Config; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.StructuredData; | ||
39 | using OpenSim.Framework; | ||
40 | using OpenSim.Framework.Servers; | ||
41 | using OpenSim.Framework.Servers.HttpServer; | ||
42 | using OpenSim.Region.Framework.Interfaces; | ||
43 | using OpenSim.Region.Framework.Scenes; | ||
44 | using OpenSim.Services.Interfaces; | ||
45 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
46 | using OpenSim.Framework.Capabilities; | ||
47 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
48 | |||
49 | namespace OpenSim.Region.ClientStack.Linden | ||
50 | { | ||
51 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "NewFileAgentInventoryVariablePriceModule")] | ||
52 | public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule | ||
53 | { | ||
54 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private Scene m_scene; | ||
57 | // private IAssetService m_assetService; | ||
58 | private bool m_dumpAssetsToFile = false; | ||
59 | private bool m_enabled = true; | ||
60 | private int m_levelUpload = 0; | ||
61 | |||
62 | #region Region Module interfaceBase Members | ||
63 | |||
64 | |||
65 | public Type ReplaceableInterface | ||
66 | { | ||
67 | get { return null; } | ||
68 | } | ||
69 | |||
70 | public void Initialise(IConfigSource source) | ||
71 | { | ||
72 | IConfig meshConfig = source.Configs["Mesh"]; | ||
73 | if (meshConfig == null) | ||
74 | return; | ||
75 | |||
76 | m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true); | ||
77 | m_levelUpload = meshConfig.GetInt("LevelUpload", 0); | ||
78 | } | ||
79 | |||
80 | public void AddRegion(Scene pScene) | ||
81 | { | ||
82 | m_scene = pScene; | ||
83 | } | ||
84 | |||
85 | public void RemoveRegion(Scene scene) | ||
86 | { | ||
87 | |||
88 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
89 | m_scene = null; | ||
90 | } | ||
91 | |||
92 | public void RegionLoaded(Scene scene) | ||
93 | { | ||
94 | |||
95 | // m_assetService = m_scene.RequestModuleInterface<IAssetService>(); | ||
96 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
97 | } | ||
98 | |||
99 | #endregion | ||
100 | |||
101 | |||
102 | #region Region Module interface | ||
103 | |||
104 | |||
105 | |||
106 | public void Close() { } | ||
107 | |||
108 | public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } } | ||
109 | |||
110 | |||
111 | public void RegisterCaps(UUID agentID, Caps caps) | ||
112 | { | ||
113 | if(!m_enabled) | ||
114 | return; | ||
115 | |||
116 | UUID capID = UUID.Random(); | ||
117 | |||
118 | // m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID); | ||
119 | caps.RegisterHandler( | ||
120 | "NewFileAgentInventoryVariablePrice", | ||
121 | new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>( | ||
122 | "POST", | ||
123 | "/CAPS/" + capID.ToString(), | ||
124 | req => NewAgentInventoryRequest(req, agentID), | ||
125 | "NewFileAgentInventoryVariablePrice", | ||
126 | agentID.ToString())); | ||
127 | } | ||
128 | |||
129 | #endregion | ||
130 | |||
131 | public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID) | ||
132 | { | ||
133 | //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit | ||
134 | // you need to be aware of this | ||
135 | |||
136 | //if (llsdRequest.asset_type == "texture" || | ||
137 | // llsdRequest.asset_type == "animation" || | ||
138 | // llsdRequest.asset_type == "sound") | ||
139 | // { | ||
140 | // check user level | ||
141 | |||
142 | ScenePresence avatar = null; | ||
143 | IClientAPI client = null; | ||
144 | m_scene.TryGetScenePresence(agentID, out avatar); | ||
145 | |||
146 | if (avatar != null) | ||
147 | { | ||
148 | client = avatar.ControllingClient; | ||
149 | |||
150 | if (avatar.UserLevel < m_levelUpload) | ||
151 | { | ||
152 | if (client != null) | ||
153 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); | ||
154 | |||
155 | LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); | ||
156 | errorResponse.rsvp = ""; | ||
157 | errorResponse.state = "error"; | ||
158 | return errorResponse; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | // check funds | ||
163 | IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>(); | ||
164 | |||
165 | if (mm != null) | ||
166 | { | ||
167 | if (!mm.UploadCovered(agentID, mm.UploadCharge)) | ||
168 | { | ||
169 | if (client != null) | ||
170 | client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); | ||
171 | |||
172 | LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); | ||
173 | errorResponse.rsvp = ""; | ||
174 | errorResponse.state = "error"; | ||
175 | return errorResponse; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | // } | ||
180 | |||
181 | string assetName = llsdRequest.name; | ||
182 | string assetDes = llsdRequest.description; | ||
183 | string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/"; | ||
184 | UUID newAsset = UUID.Random(); | ||
185 | UUID newInvItem = UUID.Random(); | ||
186 | UUID parentFolder = llsdRequest.folder_id; | ||
187 | string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/"; | ||
188 | |||
189 | AssetUploader uploader = | ||
190 | new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, | ||
191 | llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile); | ||
192 | |||
193 | MainServer.Instance.AddStreamHandler( | ||
194 | new BinaryStreamHandler( | ||
195 | "POST", | ||
196 | capsBase + uploaderPath, | ||
197 | uploader.uploaderCaps, | ||
198 | "NewFileAgentInventoryVariablePrice", | ||
199 | agentID.ToString())); | ||
200 | |||
201 | string protocol = "http://"; | ||
202 | |||
203 | if (MainServer.Instance.UseSSL) | ||
204 | protocol = "https://"; | ||
205 | |||
206 | string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase + | ||
207 | uploaderPath; | ||
208 | |||
209 | |||
210 | LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); | ||
211 | |||
212 | uploadResponse.rsvp = uploaderURL; | ||
213 | uploadResponse.state = "upload"; | ||
214 | uploadResponse.resource_cost = 0; | ||
215 | uploadResponse.upload_price = 0; | ||
216 | |||
217 | uploader.OnUpLoad += //UploadCompleteHandler; | ||
218 | |||
219 | delegate( | ||
220 | string passetName, string passetDescription, UUID passetID, | ||
221 | UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType, | ||
222 | string passetType) | ||
223 | { | ||
224 | UploadCompleteHandler(passetName, passetDescription, passetID, | ||
225 | pinventoryItem, pparentFolder, pdata, pinventoryType, | ||
226 | passetType,agentID); | ||
227 | }; | ||
228 | |||
229 | return uploadResponse; | ||
230 | } | ||
231 | |||
232 | public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, | ||
233 | UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, | ||
234 | string assetType,UUID AgentID) | ||
235 | { | ||
236 | // m_log.DebugFormat( | ||
237 | // "[NEW FILE AGENT INVENTORY VARIABLE PRICE MODULE]: Upload complete for {0}", inventoryItem); | ||
238 | |||
239 | sbyte assType = 0; | ||
240 | sbyte inType = 0; | ||
241 | |||
242 | if (inventoryType == "sound") | ||
243 | { | ||
244 | inType = 1; | ||
245 | assType = 1; | ||
246 | } | ||
247 | else if (inventoryType == "animation") | ||
248 | { | ||
249 | inType = 19; | ||
250 | assType = 20; | ||
251 | } | ||
252 | else if (inventoryType == "wearable") | ||
253 | { | ||
254 | inType = 18; | ||
255 | switch (assetType) | ||
256 | { | ||
257 | case "bodypart": | ||
258 | assType = 13; | ||
259 | break; | ||
260 | case "clothing": | ||
261 | assType = 5; | ||
262 | break; | ||
263 | } | ||
264 | } | ||
265 | else if (inventoryType == "mesh") | ||
266 | { | ||
267 | inType = (sbyte)InventoryType.Mesh; | ||
268 | assType = (sbyte)AssetType.Mesh; | ||
269 | } | ||
270 | |||
271 | AssetBase asset; | ||
272 | asset = new AssetBase(assetID, assetName, assType, AgentID.ToString()); | ||
273 | asset.Data = data; | ||
274 | |||
275 | if (m_scene.AssetService != null) | ||
276 | m_scene.AssetService.Store(asset); | ||
277 | |||
278 | InventoryItemBase item = new InventoryItemBase(); | ||
279 | item.Owner = AgentID; | ||
280 | item.CreatorId = AgentID.ToString(); | ||
281 | item.ID = inventoryItem; | ||
282 | item.AssetID = asset.FullID; | ||
283 | item.Description = assetDescription; | ||
284 | item.Name = assetName; | ||
285 | item.AssetType = assType; | ||
286 | item.InvType = inType; | ||
287 | item.Folder = parentFolder; | ||
288 | item.CurrentPermissions | ||
289 | = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer); | ||
290 | item.BasePermissions = (uint)PermissionMask.All; | ||
291 | item.EveryOnePermissions = 0; | ||
292 | item.NextPermissions = (uint)PermissionMask.All; | ||
293 | item.CreationDate = Util.UnixTimeSinceEpoch(); | ||
294 | m_scene.AddInventoryItem(item); | ||
295 | } | ||
296 | } | ||
297 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs index 94f8bc1..b044e56 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs | |||
@@ -47,7 +47,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
47 | { | 47 | { |
48 | // private static readonly ILog m_log = | 48 | // private static readonly ILog m_log = |
49 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 49 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
50 | 50 | ||
51 | private Scene m_scene; | 51 | private Scene m_scene; |
52 | 52 | ||
53 | #region INonSharedRegionModule Members | 53 | #region INonSharedRegionModule Members |
@@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
76 | } | 76 | } |
77 | 77 | ||
78 | public void Close() | 78 | public void Close() |
79 | { | 79 | { |
80 | } | 80 | } |
81 | 81 | ||
82 | public string Name | 82 | public string Name |
@@ -121,6 +121,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
121 | 121 | ||
122 | 122 | ||
123 | OSD r = OSDParser.DeserializeLLSDXml((string)request["requestbody"]); | 123 | OSD r = OSDParser.DeserializeLLSDXml((string)request["requestbody"]); |
124 | if (r.Type != OSDType.Map) // not a proper req | ||
125 | return responsedata; | ||
126 | |||
124 | //UUID session_id = UUID.Zero; | 127 | //UUID session_id = UUID.Zero; |
125 | bool bypass_raycast = false; | 128 | bool bypass_raycast = false; |
126 | uint everyone_mask = 0; | 129 | uint everyone_mask = 0; |
@@ -157,9 +160,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
157 | int state = 0; | 160 | int state = 0; |
158 | int lastattach = 0; | 161 | int lastattach = 0; |
159 | 162 | ||
160 | if (r.Type != OSDType.Map) // not a proper req | ||
161 | return responsedata; | ||
162 | |||
163 | OSDMap rm = (OSDMap)r; | 163 | OSDMap rm = (OSDMap)r; |
164 | 164 | ||
165 | if (rm.ContainsKey("ObjectData")) //v2 | 165 | if (rm.ContainsKey("ObjectData")) //v2 |
@@ -307,8 +307,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
307 | } | 307 | } |
308 | } | 308 | } |
309 | 309 | ||
310 | |||
311 | |||
312 | Vector3 pos = m_scene.GetNewRezLocation(ray_start, ray_end, ray_target_id, rotation, (bypass_raycast) ? (byte)1 : (byte)0, (ray_end_is_intersection) ? (byte)1 : (byte)0, true, scale, false); | 310 | Vector3 pos = m_scene.GetNewRezLocation(ray_start, ray_end, ray_target_id, rotation, (bypass_raycast) ? (byte)1 : (byte)0, (ray_end_is_intersection) ? (byte)1 : (byte)0, true, scale, false); |
313 | 311 | ||
314 | PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); | 312 | PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); |
@@ -359,6 +357,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
359 | rootpart.NextOwnerMask = next_owner_mask; | 357 | rootpart.NextOwnerMask = next_owner_mask; |
360 | rootpart.Material = (byte)material; | 358 | rootpart.Material = (byte)material; |
361 | 359 | ||
360 | obj.InvalidateDeepEffectivePerms(); | ||
361 | |||
362 | m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); | 362 | m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); |
363 | 363 | ||
364 | responsedata["int_response_code"] = 200; //501; //410; //404; | 364 | responsedata["int_response_code"] = 200; //501; //410; //404; |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs index 769fe28..116c51f 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs | |||
@@ -189,7 +189,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
189 | if (i == 0) | 189 | if (i == 0) |
190 | { | 190 | { |
191 | rootpos = obj.Position; | 191 | rootpos = obj.Position; |
192 | // rootrot = obj.Rotation; | 192 | // rootrot = obj.Rotation; |
193 | } | 193 | } |
194 | 194 | ||
195 | // Combine the extraparams data into it's ugly blob again.... | 195 | // Combine the extraparams data into it's ugly blob again.... |
@@ -284,6 +284,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
284 | prim.OwnerID = AgentId; | 284 | prim.OwnerID = AgentId; |
285 | prim.GroupID = obj.GroupID; | 285 | prim.GroupID = obj.GroupID; |
286 | prim.LastOwnerID = prim.OwnerID; | 286 | prim.LastOwnerID = prim.OwnerID; |
287 | prim.RezzerID = AgentId; | ||
287 | prim.CreationDate = Util.UnixTimeSinceEpoch(); | 288 | prim.CreationDate = Util.UnixTimeSinceEpoch(); |
288 | prim.Name = obj.Name; | 289 | prim.Name = obj.Name; |
289 | prim.Description = ""; | 290 | prim.Description = ""; |
@@ -320,7 +321,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
320 | pbs.TextureEntry = tmp.GetBytes(); | 321 | pbs.TextureEntry = tmp.GetBytes(); |
321 | prim.Shape = pbs; | 322 | prim.Shape = pbs; |
322 | prim.Scale = obj.Scale; | 323 | prim.Scale = obj.Scale; |
323 | 324 | ||
324 | SceneObjectGroup grp = new SceneObjectGroup(); | 325 | SceneObjectGroup grp = new SceneObjectGroup(); |
325 | 326 | ||
326 | grp.SetRootPart(prim); | 327 | grp.SetRootPart(prim); |
@@ -328,21 +329,22 @@ namespace OpenSim.Region.ClientStack.Linden | |||
328 | if (i == 0) | 329 | if (i == 0) |
329 | { | 330 | { |
330 | rootGroup = grp; | 331 | rootGroup = grp; |
331 | 332 | ||
332 | } | 333 | } |
333 | grp.AttachToScene(m_scene); | 334 | grp.AttachToScene(m_scene); |
334 | grp.AbsolutePosition = obj.Position; | 335 | grp.AbsolutePosition = obj.Position; |
335 | prim.RotationOffset = obj.Rotation; | 336 | prim.RotationOffset = obj.Rotation; |
336 | 337 | ||
338 | |||
337 | // Required for linking | 339 | // Required for linking |
338 | grp.RootPart.ClearUpdateSchedule(); | 340 | grp.RootPart.ClearUpdateSchedule(); |
339 | 341 | ||
340 | if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos)) | 342 | if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos)) |
341 | { | 343 | { |
342 | m_scene.AddSceneObject(grp); | 344 | m_scene.AddSceneObject(grp); |
343 | grp.AbsolutePosition = obj.Position; | 345 | grp.AbsolutePosition = obj.Position; |
344 | } | 346 | } |
345 | 347 | ||
346 | allparts[i] = grp; | 348 | allparts[i] = grp; |
347 | } | 349 | } |
348 | 350 | ||
@@ -358,7 +360,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
358 | pos | 360 | pos |
359 | = m_scene.GetNewRezLocation( | 361 | = m_scene.GetNewRezLocation( |
360 | Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale, false); | 362 | Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale, false); |
361 | 363 | ||
362 | responsedata["int_response_code"] = 200; //501; //410; //404; | 364 | responsedata["int_response_code"] = 200; //501; //410; //404; |
363 | responsedata["content_type"] = "text/plain"; | 365 | responsedata["content_type"] = "text/plain"; |
364 | responsedata["keepalive"] = false; | 366 | responsedata["keepalive"] = false; |
@@ -366,7 +368,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
366 | 368 | ||
367 | return responsedata; | 369 | return responsedata; |
368 | } | 370 | } |
369 | 371 | ||
370 | private string ConvertUintToBytes(uint val) | 372 | private string ConvertUintToBytes(uint val) |
371 | { | 373 | { |
372 | byte[] resultbytes = Utils.UIntToBytes(val); | 374 | byte[] resultbytes = Utils.UIntToBytes(val); |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs index 0adfa1a..f36826b 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs | |||
@@ -2,7 +2,7 @@ | |||
2 | using System.Runtime.CompilerServices; | 2 | using System.Runtime.CompilerServices; |
3 | using System.Runtime.InteropServices; | 3 | using System.Runtime.InteropServices; |
4 | 4 | ||
5 | // General Information about an assembly is controlled through the following | 5 | // General Information about an assembly is controlled through the following |
6 | // set of attributes. Change these attribute values to modify the information | 6 | // set of attributes. Change these attribute values to modify the information |
7 | // associated with an assembly. | 7 | // associated with an assembly. |
8 | [assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenCaps")] | 8 | [assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenCaps")] |
@@ -14,8 +14,8 @@ using System.Runtime.InteropServices; | |||
14 | [assembly: AssemblyTrademark("")] | 14 | [assembly: AssemblyTrademark("")] |
15 | [assembly: AssemblyCulture("")] | 15 | [assembly: AssemblyCulture("")] |
16 | 16 | ||
17 | // Setting ComVisible to false makes the types in this assembly not visible | 17 | // Setting ComVisible to false makes the types in this assembly not visible |
18 | // to COM components. If you need to access a type in this assembly from | 18 | // to COM components. If you need to access a type in this assembly from |
19 | // COM, set the ComVisible attribute to true on that type. | 19 | // COM, set the ComVisible attribute to true on that type. |
20 | [assembly: ComVisible(false)] | 20 | [assembly: ComVisible(false)] |
21 | 21 | ||
@@ -25,9 +25,9 @@ using System.Runtime.InteropServices; | |||
25 | // Version information for an assembly consists of the following four values: | 25 | // Version information for an assembly consists of the following four values: |
26 | // | 26 | // |
27 | // Major Version | 27 | // Major Version |
28 | // Minor Version | 28 | // Minor Version |
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.3.*")] | 32 | [assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] |
33 | 33 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs index a133a69..e8387e3 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs | |||
@@ -58,12 +58,14 @@ namespace OpenSim.Region.ClientStack.Linden | |||
58 | { | 58 | { |
59 | // private static readonly ILog m_log = | 59 | // private static readonly ILog m_log = |
60 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 60 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
61 | 61 | ||
62 | private Scene m_scene; | 62 | private Scene m_scene; |
63 | private IEventQueue m_eventQueue; | 63 | private IEventQueue m_eventQueue; |
64 | private Commands m_commands = new Commands(); | 64 | private Commands m_commands = new Commands(); |
65 | public ICommands Commands { get { return m_commands; } } | 65 | public ICommands Commands { get { return m_commands; } } |
66 | 66 | ||
67 | public event ConsoleMessage OnConsoleMessage; | ||
68 | |||
67 | public void Initialise(IConfigSource source) | 69 | public void Initialise(IConfigSource source) |
68 | { | 70 | { |
69 | m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help); | 71 | m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help); |
@@ -102,7 +104,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
102 | 104 | ||
103 | public void RegisterCaps(UUID agentID, Caps caps) | 105 | public void RegisterCaps(UUID agentID, Caps caps) |
104 | { | 106 | { |
105 | if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID)) | 107 | if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID) && !m_scene.Permissions.IsGod(agentID)) |
106 | return; | 108 | return; |
107 | 109 | ||
108 | UUID capID = UUID.Random(); | 110 | UUID capID = UUID.Random(); |
@@ -118,6 +120,11 @@ namespace OpenSim.Region.ClientStack.Linden | |||
118 | OSD osd = OSD.FromString(message); | 120 | OSD osd = OSD.FromString(message); |
119 | 121 | ||
120 | m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID); | 122 | m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID); |
123 | |||
124 | ConsoleMessage handlerConsoleMessage = OnConsoleMessage; | ||
125 | |||
126 | if (handlerConsoleMessage != null) | ||
127 | handlerConsoleMessage( agentID, message); | ||
121 | } | 128 | } |
122 | 129 | ||
123 | public bool RunCommand(string command, UUID invokerID) | 130 | public bool RunCommand(string command, UUID invokerID) |
@@ -148,7 +155,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
148 | 155 | ||
149 | SendConsoleOutput(agentID, reply); | 156 | SendConsoleOutput(agentID, reply); |
150 | } | 157 | } |
151 | 158 | ||
152 | public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) | 159 | public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) |
153 | { | 160 | { |
154 | m_commands.AddCommand(module, shared, command, help, longhelp, fn); | 161 | m_commands.AddCommand(module, shared, command, help, longhelp, fn); |
@@ -178,8 +185,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
178 | 185 | ||
179 | protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 186 | protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
180 | { | 187 | { |
181 | StreamReader reader = new StreamReader(request); | 188 | string message; |
182 | string message = reader.ReadToEnd(); | 189 | using(StreamReader reader = new StreamReader(request)) |
190 | message = reader.ReadToEnd(); | ||
183 | 191 | ||
184 | OSD osd = OSDParser.DeserializeLLSDXml(message); | 192 | OSD osd = OSDParser.DeserializeLLSDXml(message); |
185 | 193 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs index e258bcb..39f5baf 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs | |||
@@ -50,12 +50,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
50 | /// This is required for uploading Mesh. | 50 | /// This is required for uploading Mesh. |
51 | /// Since is accepts an open-ended response, we also send more information | 51 | /// Since is accepts an open-ended response, we also send more information |
52 | /// for viewers that care to interpret it. | 52 | /// for viewers that care to interpret it. |
53 | /// | 53 | /// |
54 | /// NOTE: Part of this code was adapted from the Aurora project, specifically | 54 | /// NOTE: Part of this code was adapted from the Aurora project, specifically |
55 | /// the normal part of the response in the capability handler. | 55 | /// the normal part of the response in the capability handler. |
56 | /// </remarks> | 56 | /// </remarks> |
57 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimulatorFeaturesModule")] | 57 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimulatorFeaturesModule")] |
58 | public class SimulatorFeaturesModule : ISharedRegionModule, ISimulatorFeaturesModule | 58 | public class SimulatorFeaturesModule : INonSharedRegionModule, ISimulatorFeaturesModule |
59 | { | 59 | { |
60 | private static readonly ILog m_log = | 60 | private static readonly ILog m_log = |
61 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 61 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -82,7 +82,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
82 | IConfig config = source.Configs["SimulatorFeatures"]; | 82 | IConfig config = source.Configs["SimulatorFeatures"]; |
83 | 83 | ||
84 | if (config != null) | 84 | if (config != null) |
85 | { | 85 | { |
86 | // | 86 | // |
87 | // All this is obsolete since getting these features from the grid service!! | 87 | // All this is obsolete since getting these features from the grid service!! |
88 | // Will be removed after the next release | 88 | // Will be removed after the next release |
@@ -126,10 +126,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
126 | GetGridExtraFeatures(s); | 126 | GetGridExtraFeatures(s); |
127 | } | 127 | } |
128 | 128 | ||
129 | public void PostInitialise() | ||
130 | { | ||
131 | } | ||
132 | |||
133 | public void Close() { } | 129 | public void Close() { } |
134 | 130 | ||
135 | public string Name { get { return "SimulatorFeaturesModule"; } } | 131 | public string Name { get { return "SimulatorFeaturesModule"; } } |
@@ -155,6 +151,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
155 | m_features["MeshRezEnabled"] = true; | 151 | m_features["MeshRezEnabled"] = true; |
156 | m_features["MeshUploadEnabled"] = true; | 152 | m_features["MeshUploadEnabled"] = true; |
157 | m_features["MeshXferEnabled"] = true; | 153 | m_features["MeshXferEnabled"] = true; |
154 | |||
158 | m_features["PhysicsMaterialsEnabled"] = true; | 155 | m_features["PhysicsMaterialsEnabled"] = true; |
159 | 156 | ||
160 | OSDMap typesMap = new OSDMap(); | 157 | OSDMap typesMap = new OSDMap(); |
@@ -173,6 +170,10 @@ namespace OpenSim.Region.ClientStack.Linden | |||
173 | else | 170 | else |
174 | extrasMap = new OSDMap(); | 171 | extrasMap = new OSDMap(); |
175 | 172 | ||
173 | extrasMap["AvatarSkeleton"] = true; | ||
174 | extrasMap["AnimationSet"] = true; | ||
175 | |||
176 | // TODO: Take these out of here into their respective modules, like map-server-url | ||
176 | if (m_SearchURL != string.Empty) | 177 | if (m_SearchURL != string.Empty) |
177 | extrasMap["search-server-url"] = m_SearchURL; | 178 | extrasMap["search-server-url"] = m_SearchURL; |
178 | if (!string.IsNullOrEmpty(m_DestinationGuideURL)) | 179 | if (!string.IsNullOrEmpty(m_DestinationGuideURL)) |
@@ -250,7 +251,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
250 | 251 | ||
251 | //Send back data | 252 | //Send back data |
252 | Hashtable responsedata = new Hashtable(); | 253 | Hashtable responsedata = new Hashtable(); |
253 | responsedata["int_response_code"] = 200; | 254 | responsedata["int_response_code"] = 200; |
254 | responsedata["content_type"] = "text/plain"; | 255 | responsedata["content_type"] = "text/plain"; |
255 | responsedata["keepalive"] = false; | 256 | responsedata["keepalive"] = false; |
256 | 257 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs index dd4a691..6ffed4d 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs | |||
@@ -52,6 +52,7 @@ using OSDMap = OpenMetaverse.StructuredData.OSDMap; | |||
52 | 52 | ||
53 | namespace OpenSim.Region.ClientStack.Linden.Caps.Tests | 53 | namespace OpenSim.Region.ClientStack.Linden.Caps.Tests |
54 | { | 54 | { |
55 | /* | ||
55 | [TestFixture] | 56 | [TestFixture] |
56 | public class WebFetchInvDescModuleTests : OpenSimTestCase | 57 | public class WebFetchInvDescModuleTests : OpenSimTestCase |
57 | { | 58 | { |
@@ -150,10 +151,11 @@ namespace OpenSim.Region.ClientStack.Linden.Caps.Tests | |||
150 | OSDMap responseOsd = (OSDMap)OSDParser.DeserializeLLSDXml(context.ResponseBody); | 151 | OSDMap responseOsd = (OSDMap)OSDParser.DeserializeLLSDXml(context.ResponseBody); |
151 | OSDArray foldersOsd = (OSDArray)responseOsd["folders"]; | 152 | OSDArray foldersOsd = (OSDArray)responseOsd["folders"]; |
152 | OSDMap folderOsd = (OSDMap)foldersOsd[0]; | 153 | OSDMap folderOsd = (OSDMap)foldersOsd[0]; |
153 | 154 | ||
154 | // A sanity check that the response has the expected number of descendents for a default inventory | 155 | // A sanity check that the response has the expected number of descendents for a default inventory |
155 | // TODO: Need a more thorough check. | 156 | // TODO: Need a more thorough check. |
156 | Assert.That((int)folderOsd["descendents"], Is.EqualTo(16)); | 157 | Assert.That((int)folderOsd["descendents"], Is.EqualTo(16)); |
157 | } | 158 | } |
158 | } | 159 | } |
160 | */ | ||
159 | } \ No newline at end of file | 161 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs index 8cdebcd..b406b37 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs | |||
@@ -63,23 +63,23 @@ namespace OpenSim.Region.ClientStack.Linden | |||
63 | private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule. | 63 | private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule. |
64 | 64 | ||
65 | private Scene m_scene; | 65 | private Scene m_scene; |
66 | private bool m_persistBakedTextures; | ||
67 | 66 | ||
68 | private IBakedTextureModule m_BakedTextureModule; | 67 | private string m_URL; |
69 | 68 | ||
70 | public void Initialise(IConfigSource source) | 69 | public void Initialise(IConfigSource source) |
71 | { | 70 | { |
72 | IConfig appearanceConfig = source.Configs["Appearance"]; | 71 | IConfig config = source.Configs["ClientStack.LindenCaps"]; |
73 | if (appearanceConfig != null) | 72 | if (config == null) |
74 | m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); | 73 | return; |
75 | 74 | ||
75 | m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty); | ||
76 | 76 | ||
77 | // IConfig appearanceConfig = source.Configs["Appearance"]; | ||
77 | } | 78 | } |
78 | 79 | ||
79 | public void AddRegion(Scene s) | 80 | public void AddRegion(Scene s) |
80 | { | 81 | { |
81 | m_scene = s; | 82 | m_scene = s; |
82 | |||
83 | } | 83 | } |
84 | 84 | ||
85 | public void RemoveRegion(Scene s) | 85 | public void RemoveRegion(Scene s) |
@@ -87,188 +87,28 @@ namespace OpenSim.Region.ClientStack.Linden | |||
87 | s.EventManager.OnRegisterCaps -= RegisterCaps; | 87 | s.EventManager.OnRegisterCaps -= RegisterCaps; |
88 | s.EventManager.OnNewPresence -= RegisterNewPresence; | 88 | s.EventManager.OnNewPresence -= RegisterNewPresence; |
89 | s.EventManager.OnRemovePresence -= DeRegisterPresence; | 89 | s.EventManager.OnRemovePresence -= DeRegisterPresence; |
90 | m_BakedTextureModule = null; | ||
91 | m_scene = null; | 90 | m_scene = null; |
92 | } | 91 | } |
93 | 92 | ||
94 | |||
95 | |||
96 | public void RegionLoaded(Scene s) | 93 | public void RegionLoaded(Scene s) |
97 | { | 94 | { |
98 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | 95 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; |
99 | m_scene.EventManager.OnNewPresence += RegisterNewPresence; | 96 | m_scene.EventManager.OnNewPresence += RegisterNewPresence; |
100 | m_scene.EventManager.OnRemovePresence += DeRegisterPresence; | 97 | m_scene.EventManager.OnRemovePresence += DeRegisterPresence; |
101 | |||
102 | } | 98 | } |
103 | 99 | ||
104 | private void DeRegisterPresence(UUID agentId) | 100 | private void DeRegisterPresence(UUID agentId) |
105 | { | 101 | { |
106 | ScenePresence presence = null; | ||
107 | if (m_scene.TryGetScenePresence(agentId, out presence)) | ||
108 | { | ||
109 | presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings; | ||
110 | } | ||
111 | |||
112 | } | 102 | } |
113 | 103 | ||
114 | private void RegisterNewPresence(ScenePresence presence) | 104 | private void RegisterNewPresence(ScenePresence presence) |
115 | { | 105 | { |
116 | presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings; | ||
117 | |||
118 | } | ||
119 | |||
120 | private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems) | ||
121 | { | ||
122 | int maxCacheitemsLoop = cacheItems.Length; | ||
123 | if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES) | ||
124 | { | ||
125 | maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES; | ||
126 | m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES); | ||
127 | } | ||
128 | |||
129 | m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>(); | ||
130 | if (cacheItems.Length > 0) | ||
131 | { | ||
132 | // m_log.Debug("[Cacheitems]: " + cacheItems.Length); | ||
133 | // for (int iter = 0; iter < maxCacheitemsLoop; iter++) | ||
134 | // { | ||
135 | // m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" + | ||
136 | // cacheItems[iter].TextureID); | ||
137 | // } | ||
138 | |||
139 | ScenePresence p = null; | ||
140 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p)) | ||
141 | { | ||
142 | |||
143 | WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems; | ||
144 | if (existingitems == null) | ||
145 | { | ||
146 | if (m_BakedTextureModule != null) | ||
147 | { | ||
148 | WearableCacheItem[] savedcache = null; | ||
149 | try | ||
150 | { | ||
151 | if (p.Appearance.WearableCacheItemsDirty) | ||
152 | { | ||
153 | savedcache = m_BakedTextureModule.Get(p.UUID); | ||
154 | p.Appearance.WearableCacheItems = savedcache; | ||
155 | p.Appearance.WearableCacheItemsDirty = false; | ||
156 | } | ||
157 | |||
158 | } | ||
159 | /* | ||
160 | * The following Catch types DO NOT WORK with m_BakedTextureModule.Get | ||
161 | * it jumps to the General Packet Exception Handler if you don't catch Exception! | ||
162 | * | ||
163 | catch (System.Net.Sockets.SocketException) | ||
164 | { | ||
165 | cacheItems = null; | ||
166 | } | ||
167 | catch (WebException) | ||
168 | { | ||
169 | cacheItems = null; | ||
170 | } | ||
171 | catch (InvalidOperationException) | ||
172 | { | ||
173 | cacheItems = null; | ||
174 | } */ | ||
175 | catch (Exception) | ||
176 | { | ||
177 | // The service logs a sufficient error message. | ||
178 | } | ||
179 | |||
180 | |||
181 | if (savedcache != null) | ||
182 | existingitems = savedcache; | ||
183 | } | ||
184 | } | ||
185 | // Existing items null means it's a fully new appearance | ||
186 | if (existingitems == null) | ||
187 | { | ||
188 | |||
189 | for (int i = 0; i < maxCacheitemsLoop; i++) | ||
190 | { | ||
191 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) | ||
192 | { | ||
193 | Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex]; | ||
194 | if (face == null) | ||
195 | { | ||
196 | textureEntry.CreateFace(cacheItems[i].TextureIndex); | ||
197 | textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID = | ||
198 | AppearanceManager.DEFAULT_AVATAR_TEXTURE; | ||
199 | continue; | ||
200 | } | ||
201 | cacheItems[i].TextureID =face.TextureID; | ||
202 | if (m_scene.AssetService != null) | ||
203 | cacheItems[i].TextureAsset = | ||
204 | m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); | ||
205 | } | ||
206 | else | ||
207 | { | ||
208 | m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length); | ||
209 | } | ||
210 | |||
211 | |||
212 | } | ||
213 | } | ||
214 | else | ||
215 | |||
216 | |||
217 | { | ||
218 | // for each uploaded baked texture | ||
219 | for (int i = 0; i < maxCacheitemsLoop; i++) | ||
220 | { | ||
221 | if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) | ||
222 | { | ||
223 | Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex]; | ||
224 | if (face == null) | ||
225 | { | ||
226 | textureEntry.CreateFace(cacheItems[i].TextureIndex); | ||
227 | textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID = | ||
228 | AppearanceManager.DEFAULT_AVATAR_TEXTURE; | ||
229 | continue; | ||
230 | } | ||
231 | cacheItems[i].TextureID = | ||
232 | face.TextureID; | ||
233 | } | ||
234 | else | ||
235 | { | ||
236 | m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | for (int i = 0; i < maxCacheitemsLoop; i++) | ||
241 | { | ||
242 | if (cacheItems[i].TextureAsset == null) | ||
243 | { | ||
244 | cacheItems[i].TextureAsset = | ||
245 | m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | |||
250 | |||
251 | |||
252 | p.Appearance.WearableCacheItems = cacheItems; | ||
253 | |||
254 | |||
255 | |||
256 | if (m_BakedTextureModule != null) | ||
257 | { | ||
258 | m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems); | ||
259 | p.Appearance.WearableCacheItemsDirty = true; | ||
260 | |||
261 | } | ||
262 | } | ||
263 | } | ||
264 | } | 106 | } |
265 | 107 | ||
266 | public void PostInitialise() | 108 | public void PostInitialise() |
267 | { | 109 | { |
268 | } | 110 | } |
269 | 111 | ||
270 | |||
271 | |||
272 | public void Close() { } | 112 | public void Close() { } |
273 | 113 | ||
274 | public string Name { get { return "UploadBakedTextureModule"; } } | 114 | public string Name { get { return "UploadBakedTextureModule"; } } |
@@ -280,23 +120,26 @@ namespace OpenSim.Region.ClientStack.Linden | |||
280 | 120 | ||
281 | public void RegisterCaps(UUID agentID, Caps caps) | 121 | public void RegisterCaps(UUID agentID, Caps caps) |
282 | { | 122 | { |
283 | UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( | 123 | //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); |
284 | caps, m_scene.AssetService, m_persistBakedTextures); | 124 | if (m_URL == "localhost") |
125 | { | ||
126 | UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( | ||
127 | caps, m_scene.AssetService); | ||
285 | 128 | ||
286 | 129 | caps.RegisterHandler( | |
287 | |||
288 | caps.RegisterHandler( | ||
289 | "UploadBakedTexture", | ||
290 | new RestStreamHandler( | ||
291 | "POST", | ||
292 | "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, | ||
293 | avatarhandler.UploadBakedTexture, | ||
294 | "UploadBakedTexture", | 130 | "UploadBakedTexture", |
295 | agentID.ToString())); | 131 | new RestStreamHandler( |
296 | 132 | "POST", | |
297 | 133 | "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, | |
298 | 134 | avatarhandler.UploadBakedTexture, | |
135 | "UploadBakedTexture", | ||
136 | agentID.ToString())); | ||
299 | 137 | ||
138 | } | ||
139 | else | ||
140 | { | ||
141 | caps.RegisterHandler("UploadBakedTexture", m_URL); | ||
142 | } | ||
300 | } | 143 | } |
301 | } | 144 | } |
302 | } | 145 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 025ffea..8d4e561 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | |||
@@ -34,9 +34,7 @@ using log4net; | |||
34 | using Nini.Config; | 34 | using Nini.Config; |
35 | using Mono.Addins; | 35 | using Mono.Addins; |
36 | using OpenMetaverse; | 36 | using OpenMetaverse; |
37 | using OpenMetaverse.StructuredData; | ||
38 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
39 | using OpenSim.Framework.Monitoring; | ||
40 | using OpenSim.Framework.Servers; | 38 | using OpenSim.Framework.Servers; |
41 | using OpenSim.Framework.Servers.HttpServer; | 39 | using OpenSim.Framework.Servers.HttpServer; |
42 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
@@ -45,6 +43,9 @@ using OpenSim.Framework.Capabilities; | |||
45 | using OpenSim.Services.Interfaces; | 43 | using OpenSim.Services.Interfaces; |
46 | using Caps = OpenSim.Framework.Capabilities.Caps; | 44 | using Caps = OpenSim.Framework.Capabilities.Caps; |
47 | using OpenSim.Capabilities.Handlers; | 45 | using OpenSim.Capabilities.Handlers; |
46 | using OpenSim.Framework.Monitoring; | ||
47 | |||
48 | using OpenMetaverse.StructuredData; | ||
48 | 49 | ||
49 | namespace OpenSim.Region.ClientStack.Linden | 50 | namespace OpenSim.Region.ClientStack.Linden |
50 | { | 51 | { |
@@ -63,7 +64,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
63 | public List<UUID> folders; | 64 | public List<UUID> folders; |
64 | } | 65 | } |
65 | 66 | ||
66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 67 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
67 | 68 | ||
68 | /// <summary> | 69 | /// <summary> |
69 | /// Control whether requests will be processed asynchronously. | 70 | /// Control whether requests will be processed asynchronously. |
@@ -92,14 +93,16 @@ namespace OpenSim.Region.ClientStack.Linden | |||
92 | private bool m_Enabled; | 93 | private bool m_Enabled; |
93 | 94 | ||
94 | private string m_fetchInventoryDescendents2Url; | 95 | private string m_fetchInventoryDescendents2Url; |
95 | private string m_webFetchInventoryDescendentsUrl; | 96 | // private string m_webFetchInventoryDescendentsUrl; |
96 | 97 | ||
97 | private static FetchInvDescHandler m_webFetchHandler; | 98 | private static FetchInvDescHandler m_webFetchHandler; |
98 | 99 | ||
99 | private static Thread[] m_workerThreads = null; | 100 | private static Thread[] m_workerThreads = null; |
100 | 101 | ||
101 | private static DoubleQueue<aPollRequest> m_queue = | 102 | private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue = |
102 | new DoubleQueue<aPollRequest>(); | 103 | new OpenSim.Framework.BlockingQueue<aPollRequest>(); |
104 | |||
105 | private static int m_NumberScenes = 0; | ||
103 | 106 | ||
104 | #region ISharedRegionModule Members | 107 | #region ISharedRegionModule Members |
105 | 108 | ||
@@ -117,9 +120,10 @@ namespace OpenSim.Region.ClientStack.Linden | |||
117 | return; | 120 | return; |
118 | 121 | ||
119 | m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); | 122 | m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); |
120 | m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); | 123 | // m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); |
121 | 124 | ||
122 | if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) | 125 | // if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) |
126 | if (m_fetchInventoryDescendents2Url != string.Empty) | ||
123 | { | 127 | { |
124 | m_Enabled = true; | 128 | m_Enabled = true; |
125 | } | 129 | } |
@@ -143,17 +147,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
143 | StatsManager.DeregisterStat(s_processedRequestsStat); | 147 | StatsManager.DeregisterStat(s_processedRequestsStat); |
144 | StatsManager.DeregisterStat(s_queuedRequestsStat); | 148 | StatsManager.DeregisterStat(s_queuedRequestsStat); |
145 | 149 | ||
146 | if (ProcessQueuedRequestsAsync) | 150 | m_NumberScenes--; |
147 | { | ||
148 | if (m_workerThreads != null) | ||
149 | { | ||
150 | foreach (Thread t in m_workerThreads) | ||
151 | Watchdog.AbortThread(t.ManagedThreadId); | ||
152 | |||
153 | m_workerThreads = null; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | Scene = null; | 151 | Scene = null; |
158 | } | 152 | } |
159 | 153 | ||
@@ -187,7 +181,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
187 | "httpfetch", | 181 | "httpfetch", |
188 | StatType.Pull, | 182 | StatType.Pull, |
189 | MeasuresOfInterest.AverageChangeOverTime, | 183 | MeasuresOfInterest.AverageChangeOverTime, |
190 | stat => { stat.Value = m_queue.Count; }, | 184 | stat => { stat.Value = m_queue.Count(); }, |
191 | StatVerbosity.Debug); | 185 | StatVerbosity.Debug); |
192 | 186 | ||
193 | StatsManager.RegisterStat(s_processedRequestsStat); | 187 | StatsManager.RegisterStat(s_processedRequestsStat); |
@@ -201,6 +195,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
201 | 195 | ||
202 | Scene.EventManager.OnRegisterCaps += RegisterCaps; | 196 | Scene.EventManager.OnRegisterCaps += RegisterCaps; |
203 | 197 | ||
198 | m_NumberScenes++; | ||
199 | |||
204 | int nworkers = 2; // was 2 | 200 | int nworkers = 2; // was 2 |
205 | if (ProcessQueuedRequestsAsync && m_workerThreads == null) | 201 | if (ProcessQueuedRequestsAsync && m_workerThreads == null) |
206 | { | 202 | { |
@@ -211,7 +207,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
211 | m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests, | 207 | m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests, |
212 | String.Format("InventoryWorkerThread{0}", i), | 208 | String.Format("InventoryWorkerThread{0}", i), |
213 | ThreadPriority.Normal, | 209 | ThreadPriority.Normal, |
214 | false, | 210 | true, |
215 | true, | 211 | true, |
216 | null, | 212 | null, |
217 | int.MaxValue); | 213 | int.MaxValue); |
@@ -223,7 +219,23 @@ namespace OpenSim.Region.ClientStack.Linden | |||
223 | { | 219 | { |
224 | } | 220 | } |
225 | 221 | ||
226 | public void Close() { } | 222 | public void Close() |
223 | { | ||
224 | if (!m_Enabled) | ||
225 | return; | ||
226 | |||
227 | if (ProcessQueuedRequestsAsync) | ||
228 | { | ||
229 | if (m_NumberScenes <= 0 && m_workerThreads != null) | ||
230 | { | ||
231 | m_log.DebugFormat("[WebFetchInvDescModule] Closing"); | ||
232 | foreach (Thread t in m_workerThreads) | ||
233 | Watchdog.AbortThread(t.ManagedThreadId); | ||
234 | |||
235 | m_workerThreads = null; | ||
236 | } | ||
237 | } | ||
238 | } | ||
227 | 239 | ||
228 | public string Name { get { return "WebFetchInvDescModule"; } } | 240 | public string Name { get { return "WebFetchInvDescModule"; } } |
229 | 241 | ||
@@ -312,16 +324,17 @@ namespace OpenSim.Region.ClientStack.Linden | |||
312 | { | 324 | { |
313 | if (!reqinfo.folders.Contains(folderID)) | 325 | if (!reqinfo.folders.Contains(folderID)) |
314 | { | 326 | { |
315 | //TODO: Port COF handling from Avination | 327 | if (sp.COF != UUID.Zero && sp.COF == folderID) |
328 | highPriority = true; | ||
316 | reqinfo.folders.Add(folderID); | 329 | reqinfo.folders.Add(folderID); |
317 | } | 330 | } |
318 | } | 331 | } |
319 | } | 332 | } |
320 | 333 | ||
321 | if (highPriority) | 334 | if (highPriority) |
322 | m_queue.EnqueueHigh(reqinfo); | 335 | m_queue.PriorityEnqueue(reqinfo); |
323 | else | 336 | else |
324 | m_queue.EnqueueLow(reqinfo); | 337 | m_queue.Enqueue(reqinfo); |
325 | }; | 338 | }; |
326 | 339 | ||
327 | NoEvents = (x, y) => | 340 | NoEvents = (x, y) => |
@@ -347,6 +360,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
347 | 360 | ||
348 | public void Process(aPollRequest requestinfo) | 361 | public void Process(aPollRequest requestinfo) |
349 | { | 362 | { |
363 | if(m_module == null || m_module.Scene == null || m_module.Scene.ShuttingDown) | ||
364 | return; | ||
365 | |||
350 | UUID requestID = requestinfo.reqID; | 366 | UUID requestID = requestinfo.reqID; |
351 | 367 | ||
352 | Hashtable response = new Hashtable(); | 368 | Hashtable response = new Hashtable(); |
@@ -365,7 +381,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
365 | m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054"); | 381 | m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054"); |
366 | responses[requestID] = response; | 382 | responses[requestID] = response; |
367 | } | 383 | } |
368 | 384 | requestinfo.folders.Clear(); | |
385 | requestinfo.request.Clear(); | ||
369 | WebFetchInvDescModule.ProcessedRequestsCount++; | 386 | WebFetchInvDescModule.ProcessedRequestsCount++; |
370 | } | 387 | } |
371 | } | 388 | } |
@@ -422,31 +439,25 @@ namespace OpenSim.Region.ClientStack.Linden | |||
422 | // } | 439 | // } |
423 | // } | 440 | // } |
424 | 441 | ||
425 | private void DoInventoryRequests() | 442 | private static void DoInventoryRequests() |
426 | { | 443 | { |
427 | while (true) | 444 | while (true) |
428 | { | 445 | { |
446 | aPollRequest poolreq = m_queue.Dequeue(4500); | ||
429 | Watchdog.UpdateThread(); | 447 | Watchdog.UpdateThread(); |
430 | 448 | ||
431 | WaitProcessQueuedInventoryRequest(); | 449 | if (poolreq != null && poolreq.thepoll != null) |
432 | } | ||
433 | } | ||
434 | |||
435 | public void WaitProcessQueuedInventoryRequest() | ||
436 | { | ||
437 | aPollRequest poolreq = m_queue.Dequeue(); | ||
438 | |||
439 | if (poolreq != null && poolreq.thepoll != null) | ||
440 | { | ||
441 | try | ||
442 | { | ||
443 | poolreq.thepoll.Process(poolreq); | ||
444 | } | ||
445 | catch (Exception e) | ||
446 | { | 450 | { |
447 | m_log.ErrorFormat( | 451 | try |
448 | "[INVENTORY]: Failed to process queued inventory request {0} for {1} in {2}. Exception {3}", | 452 | { |
449 | poolreq.reqID, poolreq.presence != null ? poolreq.presence.Name : "unknown", Scene.Name, e); | 453 | poolreq.thepoll.Process(poolreq); |
454 | } | ||
455 | catch (Exception e) | ||
456 | { | ||
457 | m_log.ErrorFormat( | ||
458 | "[INVENTORY]: Failed to process queued inventory request {0} for {1}. Exception {2}", | ||
459 | poolreq.reqID, poolreq.presence != null ? poolreq.presence.Name : "unknown", e); | ||
460 | } | ||
450 | } | 461 | } |
451 | } | 462 | } |
452 | } | 463 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs index 4d0568d..0a6785c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs | |||
@@ -98,7 +98,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
98 | } | 98 | } |
99 | 99 | ||
100 | /// <summary> | 100 | /// <summary> |
101 | /// Sends packets for this texture to a client until packetsToSend is | 101 | /// Sends packets for this texture to a client until packetsToSend is |
102 | /// hit or the transfer completes | 102 | /// hit or the transfer completes |
103 | /// </summary> | 103 | /// </summary> |
104 | /// <param name="client">Reference to the client that the packets are destined for</param> | 104 | /// <param name="client">Reference to the client that the packets are destined for</param> |
@@ -198,7 +198,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
198 | m_currentPacket = m_stopPacket; | 198 | m_currentPacket = m_stopPacket; |
199 | return; | 199 | return; |
200 | } | 200 | } |
201 | 201 | ||
202 | if (DiscardLevel >= 0 || m_stopPacket == 0) | 202 | if (DiscardLevel >= 0 || m_stopPacket == 0) |
203 | { | 203 | { |
204 | // This shouldn't happen, but if it does, we really can't proceed | 204 | // This shouldn't happen, but if it does, we really can't proceed |
@@ -234,6 +234,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
234 | m_stopPacket = TexturePacketCount(); | 234 | m_stopPacket = TexturePacketCount(); |
235 | } | 235 | } |
236 | 236 | ||
237 | //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way) | ||
238 | if (m_stopPacket == 1 && m_layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++; | ||
239 | |||
237 | m_currentPacket = StartPacket; | 240 | m_currentPacket = StartPacket; |
238 | } | 241 | } |
239 | } | 242 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index b17b822..c18f587 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -62,7 +62,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
62 | /// Handles new client connections | 62 | /// Handles new client connections |
63 | /// Constructor takes a single Packet and authenticates everything | 63 | /// Constructor takes a single Packet and authenticates everything |
64 | /// </summary> | 64 | /// </summary> |
65 | public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientInventory, IStatsCollector | 65 | public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientInventory, IStatsCollector, IClientIPEndpoint |
66 | { | 66 | { |
67 | /// <value> | 67 | /// <value> |
68 | /// Debug packet level. See OpenSim.RegisterConsoleCommands() for more details. | 68 | /// Debug packet level. See OpenSim.RegisterConsoleCommands() for more details. |
@@ -80,6 +80,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
80 | public event ChatMessage OnChatFromClient; | 80 | public event ChatMessage OnChatFromClient; |
81 | public event RezObject OnRezObject; | 81 | public event RezObject OnRezObject; |
82 | public event DeRezObject OnDeRezObject; | 82 | public event DeRezObject OnDeRezObject; |
83 | public event RezRestoreToWorld OnRezRestoreToWorld; | ||
83 | public event ModifyTerrain OnModifyTerrain; | 84 | public event ModifyTerrain OnModifyTerrain; |
84 | public event Action<IClientAPI> OnRegionHandShakeReply; | 85 | public event Action<IClientAPI> OnRegionHandShakeReply; |
85 | public event GenericCall1 OnRequestWearables; | 86 | public event GenericCall1 OnRequestWearables; |
@@ -100,6 +101,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
100 | public event AvatarPickerRequest OnAvatarPickerRequest; | 101 | public event AvatarPickerRequest OnAvatarPickerRequest; |
101 | public event StartAnim OnStartAnim; | 102 | public event StartAnim OnStartAnim; |
102 | public event StopAnim OnStopAnim; | 103 | public event StopAnim OnStopAnim; |
104 | public event ChangeAnim OnChangeAnim; | ||
103 | public event Action<IClientAPI> OnRequestAvatarsData; | 105 | public event Action<IClientAPI> OnRequestAvatarsData; |
104 | public event LinkObjects OnLinkObjects; | 106 | public event LinkObjects OnLinkObjects; |
105 | public event DelinkObjects OnDelinkObjects; | 107 | public event DelinkObjects OnDelinkObjects; |
@@ -127,6 +129,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
127 | public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; | 129 | public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; |
128 | public event UpdatePrimFlags OnUpdatePrimFlags; | 130 | public event UpdatePrimFlags OnUpdatePrimFlags; |
129 | public event UpdatePrimTexture OnUpdatePrimTexture; | 131 | public event UpdatePrimTexture OnUpdatePrimTexture; |
132 | public event ClientChangeObject onClientChangeObject; | ||
130 | public event UpdateVector OnUpdatePrimGroupPosition; | 133 | public event UpdateVector OnUpdatePrimGroupPosition; |
131 | public event UpdateVector OnUpdatePrimSinglePosition; | 134 | public event UpdateVector OnUpdatePrimSinglePosition; |
132 | public event UpdatePrimRotation OnUpdatePrimGroupRotation; | 135 | public event UpdatePrimRotation OnUpdatePrimGroupRotation; |
@@ -156,6 +159,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
156 | public event RequestTaskInventory OnRequestTaskInventory; | 159 | public event RequestTaskInventory OnRequestTaskInventory; |
157 | public event UpdateInventoryItem OnUpdateInventoryItem; | 160 | public event UpdateInventoryItem OnUpdateInventoryItem; |
158 | public event CopyInventoryItem OnCopyInventoryItem; | 161 | public event CopyInventoryItem OnCopyInventoryItem; |
162 | public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy; | ||
159 | public event MoveInventoryItem OnMoveInventoryItem; | 163 | public event MoveInventoryItem OnMoveInventoryItem; |
160 | public event RemoveInventoryItem OnRemoveInventoryItem; | 164 | public event RemoveInventoryItem OnRemoveInventoryItem; |
161 | public event RemoveInventoryFolder OnRemoveInventoryFolder; | 165 | public event RemoveInventoryFolder OnRemoveInventoryFolder; |
@@ -250,7 +254,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
250 | public event ClassifiedInfoRequest OnClassifiedInfoRequest; | 254 | public event ClassifiedInfoRequest OnClassifiedInfoRequest; |
251 | public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; | 255 | public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; |
252 | public event ClassifiedDelete OnClassifiedDelete; | 256 | public event ClassifiedDelete OnClassifiedDelete; |
253 | public event ClassifiedDelete OnClassifiedGodDelete; | 257 | public event ClassifiedGodDelete OnClassifiedGodDelete; |
254 | public event EventNotificationAddRequest OnEventNotificationAddRequest; | 258 | public event EventNotificationAddRequest OnEventNotificationAddRequest; |
255 | public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; | 259 | public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; |
256 | public event EventGodDelete OnEventGodDelete; | 260 | public event EventGodDelete OnEventGodDelete; |
@@ -281,10 +285,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
281 | public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; | 285 | public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; |
282 | public event SimWideDeletesDelegate OnSimWideDeletes; | 286 | public event SimWideDeletesDelegate OnSimWideDeletes; |
283 | public event SendPostcard OnSendPostcard; | 287 | public event SendPostcard OnSendPostcard; |
288 | public event ChangeInventoryItemFlags OnChangeInventoryItemFlags; | ||
284 | public event MuteListEntryUpdate OnUpdateMuteListEntry; | 289 | public event MuteListEntryUpdate OnUpdateMuteListEntry; |
285 | public event MuteListEntryRemove OnRemoveMuteListEntry; | 290 | public event MuteListEntryRemove OnRemoveMuteListEntry; |
286 | public event GodlikeMessage onGodlikeMessage; | 291 | public event GodlikeMessage onGodlikeMessage; |
287 | public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; | 292 | public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; |
293 | public event GenericCall2 OnUpdateThrottles; | ||
288 | 294 | ||
289 | #pragma warning disable 0067 | 295 | #pragma warning disable 0067 |
290 | public event GenericMessage OnGenericMessage; | 296 | public event GenericMessage OnGenericMessage; |
@@ -319,6 +325,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
319 | /// </summary> | 325 | /// </summary> |
320 | public LLImageManager ImageManager { get; private set; } | 326 | public LLImageManager ImageManager { get; private set; } |
321 | 327 | ||
328 | public JobEngine m_asyncPacketProcess; | ||
322 | private readonly LLUDPServer m_udpServer; | 329 | private readonly LLUDPServer m_udpServer; |
323 | private readonly LLUDPClient m_udpClient; | 330 | private readonly LLUDPClient m_udpClient; |
324 | private readonly UUID m_sessionId; | 331 | private readonly UUID m_sessionId; |
@@ -328,31 +335,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
328 | private readonly byte[] m_channelVersion = Utils.EmptyBytes; | 335 | private readonly byte[] m_channelVersion = Utils.EmptyBytes; |
329 | private readonly IGroupsModule m_GroupsModule; | 336 | private readonly IGroupsModule m_GroupsModule; |
330 | 337 | ||
331 | private int m_cachedTextureSerial; | 338 | // private int m_cachedTextureSerial; |
332 | private PriorityQueue m_entityUpdates; | 339 | private PriorityQueue m_entityUpdates; |
333 | private PriorityQueue m_entityProps; | 340 | private PriorityQueue m_entityProps; |
334 | private Prioritizer m_prioritizer; | 341 | private Prioritizer m_prioritizer; |
335 | private bool m_disableFacelights = false; | 342 | private bool m_disableFacelights = false; |
336 | private volatile bool m_justEditedTerrain = false; | 343 | |
337 | /// <value> | 344 | // needs optimazation |
338 | /// List used in construction of data blocks for an object update packet. This is to stop us having to | 345 | private HashSet<SceneObjectGroup> GroupsInView = new HashSet<SceneObjectGroup>(); |
339 | /// continually recreate it. | 346 | |
340 | /// </value> | 347 | // private bool m_VelocityInterpolate = false; |
341 | protected List<ObjectUpdatePacket.ObjectDataBlock> m_fullUpdateDataBlocksBuilder; | 348 | private const uint MaxTransferBytesPerPacket = 600; |
342 | 349 | ||
343 | /// <value> | 350 | /// <value> |
344 | /// Maintain a record of all the objects killed. This allows us to stop an update being sent from the | 351 | /// Maintain a record of all the objects killed. This allows us to stop an update being sent from the |
345 | /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an | 352 | /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an |
346 | /// ownerless phantom. | 353 | /// ownerless phantom. |
347 | /// | 354 | /// |
348 | /// All manipulation of this set has to occur under a lock | 355 | /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock |
349 | /// | 356 | /// |
350 | /// </value> | 357 | /// </value> |
351 | protected HashSet<uint> m_killRecord; | 358 | protected List<uint> m_killRecord; |
352 | 359 | ||
353 | // protected HashSet<uint> m_attachmentsSent; | 360 | // protected HashSet<uint> m_attachmentsSent; |
354 | 361 | ||
355 | private int m_animationSequenceNumber = 1; | 362 | private bool m_deliverPackets = true; |
363 | |||
356 | private bool m_SendLogoutPacketWhenClosing = true; | 364 | private bool m_SendLogoutPacketWhenClosing = true; |
357 | 365 | ||
358 | /// <summary> | 366 | /// <summary> |
@@ -371,7 +379,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
371 | protected Scene m_scene; | 379 | protected Scene m_scene; |
372 | protected string m_firstName; | 380 | protected string m_firstName; |
373 | protected string m_lastName; | 381 | protected string m_lastName; |
374 | protected Thread m_clientThread; | ||
375 | protected Vector3 m_startpos; | 382 | protected Vector3 m_startpos; |
376 | protected UUID m_activeGroupID; | 383 | protected UUID m_activeGroupID; |
377 | protected string m_activeGroupName = String.Empty; | 384 | protected string m_activeGroupName = String.Empty; |
@@ -398,18 +405,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
398 | get { return m_startpos; } | 405 | get { return m_startpos; } |
399 | set { m_startpos = value; } | 406 | set { m_startpos = value; } |
400 | } | 407 | } |
408 | public bool DeliverPackets | ||
409 | { | ||
410 | get { return m_deliverPackets; } | ||
411 | set { | ||
412 | m_deliverPackets = value; | ||
413 | m_udpClient.m_deliverPackets = value; | ||
414 | } | ||
415 | } | ||
401 | public UUID AgentId { get { return m_agentId; } } | 416 | public UUID AgentId { get { return m_agentId; } } |
402 | public ISceneAgent SceneAgent { get; set; } | 417 | public ISceneAgent SceneAgent { get; set; } |
403 | public UUID ActiveGroupId { get { return m_activeGroupID; } private set { m_activeGroupID = value; } } | 418 | public UUID ActiveGroupId { get { return m_activeGroupID; } set { m_activeGroupID = value; } } |
404 | public string ActiveGroupName { get { return m_activeGroupName; } private set { m_activeGroupName = value; } } | 419 | public string ActiveGroupName { get { return m_activeGroupName; } set { m_activeGroupName = value; } } |
405 | public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } private set { m_activeGroupPowers = value; } } | 420 | public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } set { m_activeGroupPowers = value; } } |
406 | public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } | 421 | public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } |
407 | 422 | ||
423 | public int PingTimeMS | ||
424 | { | ||
425 | get | ||
426 | { | ||
427 | if (UDPClient != null) | ||
428 | return UDPClient.PingTimeMS; | ||
429 | return 0; | ||
430 | } | ||
431 | } | ||
432 | |||
408 | /// <summary> | 433 | /// <summary> |
409 | /// Entity update queues | 434 | /// Entity update queues |
410 | /// </summary> | 435 | /// </summary> |
411 | public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } } | 436 | public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } } |
412 | 437 | ||
413 | /// <summary> | 438 | /// <summary> |
414 | /// First name of the agent/avatar represented by the client | 439 | /// First name of the agent/avatar represented by the client |
415 | /// </summary> | 440 | /// </summary> |
@@ -426,7 +451,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
426 | public string Name { get { return FirstName + " " + LastName; } } | 451 | public string Name { get { return FirstName + " " + LastName; } } |
427 | 452 | ||
428 | public uint CircuitCode { get { return m_circuitCode; } } | 453 | public uint CircuitCode { get { return m_circuitCode; } } |
429 | public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } | 454 | public int NextAnimationSequenceNumber |
455 | { | ||
456 | get { return m_udpServer.NextAnimationSequenceNumber; } | ||
457 | } | ||
430 | 458 | ||
431 | /// <summary> | 459 | /// <summary> |
432 | /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to | 460 | /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to |
@@ -447,8 +475,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
447 | set { m_disableFacelights = value; } | 475 | set { m_disableFacelights = value; } |
448 | } | 476 | } |
449 | 477 | ||
478 | public List<uint> SelectedObjects {get; private set;} | ||
479 | |||
450 | public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } | 480 | public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } |
451 | 481 | ||
482 | |||
452 | #endregion Properties | 483 | #endregion Properties |
453 | 484 | ||
454 | // ~LLClientView() | 485 | // ~LLClientView() |
@@ -465,6 +496,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
465 | // DebugPacketLevel = 1; | 496 | // DebugPacketLevel = 1; |
466 | 497 | ||
467 | CloseSyncLock = new Object(); | 498 | CloseSyncLock = new Object(); |
499 | SelectedObjects = new List<uint>(); | ||
468 | 500 | ||
469 | RegisterInterface<IClientIM>(this); | 501 | RegisterInterface<IClientIM>(this); |
470 | RegisterInterface<IClientInventory>(this); | 502 | RegisterInterface<IClientInventory>(this); |
@@ -473,8 +505,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
473 | m_scene = scene; | 505 | m_scene = scene; |
474 | m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); | 506 | m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); |
475 | m_entityProps = new PriorityQueue(m_scene.Entities.Count); | 507 | m_entityProps = new PriorityQueue(m_scene.Entities.Count); |
476 | m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); | 508 | m_killRecord = new List<uint>(); |
477 | m_killRecord = new HashSet<uint>(); | ||
478 | // m_attachmentsSent = new HashSet<uint>(); | 509 | // m_attachmentsSent = new HashSet<uint>(); |
479 | 510 | ||
480 | m_assetService = m_scene.RequestModuleInterface<IAssetService>(); | 511 | m_assetService = m_scene.RequestModuleInterface<IAssetService>(); |
@@ -498,18 +529,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
498 | m_prioritizer = new Prioritizer(m_scene); | 529 | m_prioritizer = new Prioritizer(m_scene); |
499 | 530 | ||
500 | RegisterLocalPacketHandlers(); | 531 | RegisterLocalPacketHandlers(); |
501 | 532 | string name = string.Format("AsyncInUDP-{0}",m_agentId.ToString()); | |
533 | m_asyncPacketProcess = new JobEngine(name, name, 10000); | ||
502 | IsActive = true; | 534 | IsActive = true; |
503 | } | 535 | } |
504 | 536 | ||
505 | #region Client Methods | 537 | #region Client Methods |
506 | 538 | ||
539 | |||
540 | /// <summary> | ||
541 | /// Close down the client view | ||
542 | /// </summary> | ||
507 | public void Close() | 543 | public void Close() |
508 | { | 544 | { |
509 | Close(false); | 545 | Close(true, false); |
510 | } | 546 | } |
511 | 547 | ||
512 | public void Close(bool force) | 548 | public void Close(bool sendStop, bool force) |
513 | { | 549 | { |
514 | // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. | 550 | // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. |
515 | // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. | 551 | // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. |
@@ -519,14 +555,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
519 | // there is some unidentified connection problem, not where we have issues due to deadlock | 555 | // there is some unidentified connection problem, not where we have issues due to deadlock |
520 | if (!IsActive && !force) | 556 | if (!IsActive && !force) |
521 | { | 557 | { |
522 | m_log.DebugFormat( "{0} Not attempting to close inactive client {1} in {2} since force flag is not set", | 558 | m_log.DebugFormat( "{0} Not attempting to close inactive client {1} in {2} since force flag is not set", |
523 | LogHeader, Name, m_scene.Name); | 559 | LogHeader, Name, m_scene.Name); |
524 | 560 | ||
525 | return; | 561 | return; |
526 | } | 562 | } |
527 | 563 | ||
528 | IsActive = false; | 564 | IsActive = false; |
529 | CloseWithoutChecks(); | 565 | CloseWithoutChecks(sendStop); |
530 | } | 566 | } |
531 | } | 567 | } |
532 | 568 | ||
@@ -539,19 +575,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
539 | /// | 575 | /// |
540 | /// Callers must lock ClosingSyncLock before calling. | 576 | /// Callers must lock ClosingSyncLock before calling. |
541 | /// </remarks> | 577 | /// </remarks> |
542 | public void CloseWithoutChecks() | 578 | public void CloseWithoutChecks(bool sendStop) |
543 | { | 579 | { |
544 | m_log.DebugFormat( | 580 | m_log.DebugFormat( |
545 | "[CLIENT]: Close has been called for {0} attached to scene {1}", | 581 | "[CLIENT]: Close has been called for {0} attached to scene {1}", |
546 | Name, m_scene.RegionInfo.RegionName); | 582 | Name, m_scene.RegionInfo.RegionName); |
547 | 583 | ||
548 | // Shutdown the image manager | 584 | if (sendStop) |
549 | ImageManager.Close(); | 585 | { |
586 | // Send the STOP packet | ||
587 | DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); | ||
588 | OutPacket(disable, ThrottleOutPacketType.Unknown); | ||
589 | } | ||
590 | |||
550 | 591 | ||
551 | // Fire the callback for this connection closing | 592 | // Fire the callback for this connection closing |
552 | if (OnConnectionClosed != null) | 593 | if (OnConnectionClosed != null) |
553 | OnConnectionClosed(this); | 594 | OnConnectionClosed(this); |
554 | 595 | ||
596 | m_asyncPacketProcess.Stop(); | ||
597 | |||
555 | // Flush all of the packets out of the UDP server for this client | 598 | // Flush all of the packets out of the UDP server for this client |
556 | if (m_udpServer != null) | 599 | if (m_udpServer != null) |
557 | m_udpServer.Flush(m_udpClient); | 600 | m_udpServer.Flush(m_udpClient); |
@@ -565,11 +608,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
565 | //m_scene.CloseAllAgents(CircuitCode); | 608 | //m_scene.CloseAllAgents(CircuitCode); |
566 | 609 | ||
567 | // Disable UDP handling for this client | 610 | // Disable UDP handling for this client |
611 | m_udpClient.OnQueueEmpty -= HandleQueueEmpty; | ||
612 | m_udpClient.HasUpdates -= HandleHasUpdates; | ||
613 | m_udpClient.OnPacketStats -= PopulateStats; | ||
568 | m_udpClient.Shutdown(); | 614 | m_udpClient.Shutdown(); |
569 | 615 | ||
570 | //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); | 616 | // Shutdown the image manager |
571 | //GC.Collect(); | 617 | ImageManager.Close(); |
572 | //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); | 618 | ImageManager = null; |
619 | |||
620 | m_entityUpdates = new PriorityQueue(1); | ||
621 | m_entityProps = new PriorityQueue(1); | ||
622 | m_killRecord.Clear(); | ||
623 | GroupsInView.Clear(); | ||
624 | |||
625 | if(m_scene.GetNumberOfClients() == 0) | ||
626 | { | ||
627 | GC.Collect(); | ||
628 | GC.WaitForPendingFinalizers(); | ||
629 | GC.Collect(); | ||
630 | } | ||
573 | } | 631 | } |
574 | 632 | ||
575 | public void Kick(string message) | 633 | public void Kick(string message) |
@@ -648,36 +706,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
648 | /// <returns>true if the handler was added. This is currently always the case.</returns> | 706 | /// <returns>true if the handler was added. This is currently always the case.</returns> |
649 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync) | 707 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync) |
650 | { | 708 | { |
651 | return AddLocalPacketHandler(packetType, handler, doAsync, false); | ||
652 | } | ||
653 | |||
654 | /// <summary> | ||
655 | /// Add a handler for the given packet type. | ||
656 | /// </summary> | ||
657 | /// <param name="packetType"></param> | ||
658 | /// <param name="handler"></param> | ||
659 | /// <param name="doAsync"> | ||
660 | /// If true, when the packet is received handle it on a different thread. Whether this is given direct to | ||
661 | /// a threadpool thread or placed in a queue depends on the inEngine parameter. | ||
662 | /// </param> | ||
663 | /// <param name="inEngine"> | ||
664 | /// If async is false then this parameter is ignored. | ||
665 | /// If async is true and inEngine is false, then the packet is sent directly to a | ||
666 | /// threadpool thread. | ||
667 | /// If async is true and inEngine is true, then the packet is sent to the IncomingPacketAsyncHandlingEngine. | ||
668 | /// This may result in slower handling but reduces the risk of overloading the simulator when there are many | ||
669 | /// simultaneous async requests. | ||
670 | /// </param> | ||
671 | /// <returns>true if the handler was added. This is currently always the case.</returns> | ||
672 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync, bool inEngine) | ||
673 | { | ||
674 | bool result = false; | 709 | bool result = false; |
675 | lock (m_packetHandlers) | 710 | lock (m_packetHandlers) |
676 | { | 711 | { |
677 | if (!m_packetHandlers.ContainsKey(packetType)) | 712 | if (!m_packetHandlers.ContainsKey(packetType)) |
678 | { | 713 | { |
679 | m_packetHandlers.Add( | 714 | m_packetHandlers.Add( |
680 | packetType, new PacketProcessor() { method = handler, Async = doAsync, InEngine = inEngine }); | 715 | packetType, new PacketProcessor() { method = handler, Async = doAsync}); |
681 | result = true; | 716 | result = true; |
682 | } | 717 | } |
683 | } | 718 | } |
@@ -712,30 +747,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
712 | PacketProcessor pprocessor; | 747 | PacketProcessor pprocessor; |
713 | if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor)) | 748 | if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor)) |
714 | { | 749 | { |
715 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
716 | 750 | ||
717 | //there is a local handler for this packet type | 751 | //there is a local handler for this packet type |
718 | if (pprocessor.Async) | 752 | if (pprocessor.Async) |
719 | { | 753 | { |
720 | if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString())) | ||
721 | cinfo.AsyncRequests[packet.Type.ToString()] = 0; | ||
722 | cinfo.AsyncRequests[packet.Type.ToString()]++; | ||
723 | |||
724 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); | 754 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); |
725 | 755 | m_asyncPacketProcess.QueueJob(packet.Type.ToString(), () => ProcessSpecificPacketAsync(obj)); | |
726 | if (pprocessor.InEngine) | ||
727 | m_udpServer.IpahEngine.QueueJob(packet.Type.ToString(), () => ProcessSpecificPacketAsync(obj)); | ||
728 | else | ||
729 | Util.FireAndForget(ProcessSpecificPacketAsync, obj, packet.Type.ToString()); | ||
730 | |||
731 | result = true; | 756 | result = true; |
732 | } | 757 | } |
733 | else | 758 | else |
734 | { | 759 | { |
735 | if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString())) | ||
736 | cinfo.SyncRequests[packet.Type.ToString()] = 0; | ||
737 | cinfo.SyncRequests[packet.Type.ToString()]++; | ||
738 | |||
739 | result = pprocessor.method(this, packet); | 760 | result = pprocessor.method(this, packet); |
740 | } | 761 | } |
741 | } | 762 | } |
@@ -750,11 +771,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
750 | } | 771 | } |
751 | if (found) | 772 | if (found) |
752 | { | 773 | { |
753 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
754 | if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString())) | ||
755 | cinfo.GenericRequests[packet.Type.ToString()] = 0; | ||
756 | cinfo.GenericRequests[packet.Type.ToString()]++; | ||
757 | |||
758 | result = method(this, packet); | 774 | result = method(this, packet); |
759 | } | 775 | } |
760 | } | 776 | } |
@@ -774,7 +790,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
774 | // Make sure that we see any exception caused by the asynchronous operation. | 790 | // Make sure that we see any exception caused by the asynchronous operation. |
775 | m_log.Error( | 791 | m_log.Error( |
776 | string.Format( | 792 | string.Format( |
777 | "[LLCLIENTVIEW]: Caught exception while processing {0} for {1} ", packetObject.Pack, Name), | 793 | "[LLCLIENTVIEW]: Caught exception while processing {0} for {1} ", packetObject.Pack, Name), |
778 | e); | 794 | e); |
779 | } | 795 | } |
780 | } | 796 | } |
@@ -785,9 +801,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
785 | 801 | ||
786 | public virtual void Start() | 802 | public virtual void Start() |
787 | { | 803 | { |
804 | m_asyncPacketProcess.Start(); | ||
788 | m_scene.AddNewAgent(this, PresenceType.User); | 805 | m_scene.AddNewAgent(this, PresenceType.User); |
789 | 806 | ||
790 | RefreshGroupMembership(); | 807 | // RefreshGroupMembership(); |
791 | } | 808 | } |
792 | 809 | ||
793 | # endregion | 810 | # endregion |
@@ -858,6 +875,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
858 | 875 | ||
859 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) | 876 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) |
860 | { | 877 | { |
878 | m_thisAgentUpdateArgs.CameraAtAxis.X = float.MinValue; | ||
879 | // m_thisAgentUpdateArgs.ControlFlags = uint.MaxValue; | ||
880 | m_thisAgentUpdateArgs.ControlFlags = 0; | ||
881 | |||
861 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); | 882 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); |
862 | mov.SimData.ChannelVersion = m_channelVersion; | 883 | mov.SimData.ChannelVersion = m_channelVersion; |
863 | mov.AgentData.SessionID = m_sessionId; | 884 | mov.AgentData.SessionID = m_sessionId; |
@@ -893,14 +914,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
893 | reply.ChatData.OwnerID = ownerID; | 914 | reply.ChatData.OwnerID = ownerID; |
894 | reply.ChatData.SourceID = fromAgentID; | 915 | reply.ChatData.SourceID = fromAgentID; |
895 | 916 | ||
896 | OutPacket(reply, ThrottleOutPacketType.Task); | 917 | OutPacket(reply, ThrottleOutPacketType.Unknown); |
897 | } | 918 | } |
898 | 919 | ||
899 | /// <summary> | 920 | /// <summary> |
900 | /// Send an instant message to this client | 921 | /// Send an instant message to this client |
901 | /// </summary> | 922 | /// </summary> |
902 | // | 923 | // |
903 | // Don't remove transaction ID! Groups and item gives need to set it! | ||
904 | public void SendInstantMessage(GridInstantMessage im) | 924 | public void SendInstantMessage(GridInstantMessage im) |
905 | { | 925 | { |
906 | if (((Scene)(m_scene)).Permissions.CanInstantMessage(new UUID(im.fromAgentID), new UUID(im.toAgentID))) | 926 | if (((Scene)(m_scene)).Permissions.CanInstantMessage(new UUID(im.fromAgentID), new UUID(im.toAgentID))) |
@@ -913,6 +933,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
913 | msg.MessageBlock.FromAgentName = Util.StringToBytes256(im.fromAgentName); | 933 | msg.MessageBlock.FromAgentName = Util.StringToBytes256(im.fromAgentName); |
914 | msg.MessageBlock.Dialog = im.dialog; | 934 | msg.MessageBlock.Dialog = im.dialog; |
915 | msg.MessageBlock.FromGroup = im.fromGroup; | 935 | msg.MessageBlock.FromGroup = im.fromGroup; |
936 | // this is odd | ||
916 | if (im.imSessionID == UUID.Zero.Guid) | 937 | if (im.imSessionID == UUID.Zero.Guid) |
917 | msg.MessageBlock.ID = new UUID(im.fromAgentID) ^ new UUID(im.toAgentID); | 938 | msg.MessageBlock.ID = new UUID(im.fromAgentID) ^ new UUID(im.toAgentID); |
918 | else | 939 | else |
@@ -926,32 +947,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
926 | msg.MessageBlock.Message = Util.StringToBytes1024(im.message); | 947 | msg.MessageBlock.Message = Util.StringToBytes1024(im.message); |
927 | msg.MessageBlock.BinaryBucket = im.binaryBucket; | 948 | msg.MessageBlock.BinaryBucket = im.binaryBucket; |
928 | 949 | ||
929 | if (im.message.StartsWith("[grouptest]")) | 950 | OutPacket(msg, ThrottleOutPacketType.Task); |
930 | { // this block is test code for implementing group IM - delete when group IM is finished | ||
931 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); | ||
932 | if (eq != null) | ||
933 | { | ||
934 | im.dialog = 17; | ||
935 | |||
936 | //eq.ChatterboxInvitation( | ||
937 | // new UUID("00000000-68f9-1111-024e-222222111123"), | ||
938 | // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0, | ||
939 | // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket); | ||
940 | |||
941 | eq.ChatterboxInvitation( | ||
942 | new UUID("00000000-68f9-1111-024e-222222111123"), | ||
943 | "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0, | ||
944 | false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing")); | ||
945 | |||
946 | eq.ChatterBoxSessionAgentListUpdates( | ||
947 | new UUID("00000000-68f9-1111-024e-222222111123"), | ||
948 | new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false); | ||
949 | } | ||
950 | |||
951 | Console.WriteLine("SendInstantMessage: " + msg); | ||
952 | } | ||
953 | else | ||
954 | OutPacket(msg, ThrottleOutPacketType.Task); | ||
955 | } | 951 | } |
956 | } | 952 | } |
957 | 953 | ||
@@ -1182,6 +1178,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1182 | OutPacket(GATRP, ThrottleOutPacketType.Task); | 1178 | OutPacket(GATRP, ThrottleOutPacketType.Task); |
1183 | } | 1179 | } |
1184 | 1180 | ||
1181 | |||
1182 | public virtual bool CanSendLayerData() | ||
1183 | { | ||
1184 | int n = m_udpClient.GetPacketsQueuedCount(ThrottleOutPacketType.Land); | ||
1185 | if ( n > 128) | ||
1186 | return false; | ||
1187 | return true; | ||
1188 | } | ||
1189 | |||
1185 | /// <summary> | 1190 | /// <summary> |
1186 | /// Send the region heightmap to the client | 1191 | /// Send the region heightmap to the client |
1187 | /// This method is only called when not doing intellegent terrain patch sending and | 1192 | /// This method is only called when not doing intellegent terrain patch sending and |
@@ -1192,6 +1197,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1192 | public virtual void SendLayerData(float[] map) | 1197 | public virtual void SendLayerData(float[] map) |
1193 | { | 1198 | { |
1194 | Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData(), "LLClientView.DoSendLayerData"); | 1199 | Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData(), "LLClientView.DoSendLayerData"); |
1200 | |||
1201 | // Send it sync, and async. It's not that much data | ||
1202 | // and it improves user experience just so much! | ||
1203 | // DoSendLayerData(map); | ||
1195 | } | 1204 | } |
1196 | 1205 | ||
1197 | /// <summary> | 1206 | /// <summary> |
@@ -1214,7 +1223,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1214 | //} | 1223 | //} |
1215 | 1224 | ||
1216 | // Send LayerData in a spiral pattern. Fun! | 1225 | // Send LayerData in a spiral pattern. Fun! |
1217 | SendLayerTopRight(map, 0, 0, map.SizeX/Constants.TerrainPatchSize-1, map.SizeY/Constants.TerrainPatchSize-1); | 1226 | SendLayerTopRight(map, 0, 0, map.SizeX / Constants.TerrainPatchSize - 1, map.SizeY / Constants.TerrainPatchSize - 1); |
1218 | } | 1227 | } |
1219 | catch (Exception e) | 1228 | catch (Exception e) |
1220 | { | 1229 | { |
@@ -1250,27 +1259,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1250 | SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1); | 1259 | SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1); |
1251 | } | 1260 | } |
1252 | 1261 | ||
1253 | /// <summary> | ||
1254 | /// Sends a set of four patches (x, x+1, ..., x+3) to the client | ||
1255 | /// </summary> | ||
1256 | /// <param name="map">heightmap</param> | ||
1257 | /// <param name="px">X coordinate for patches 0..12</param> | ||
1258 | /// <param name="py">Y coordinate for patches 0..15</param> | ||
1259 | // private void SendLayerPacket(float[] map, int y, int x) | ||
1260 | // { | ||
1261 | // int[] patches = new int[4]; | ||
1262 | // patches[0] = x + 0 + y * 16; | ||
1263 | // patches[1] = x + 1 + y * 16; | ||
1264 | // patches[2] = x + 2 + y * 16; | ||
1265 | // patches[3] = x + 3 + y * 16; | ||
1266 | |||
1267 | // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); | ||
1268 | // OutPacket(layerpack, ThrottleOutPacketType.Land); | ||
1269 | // } | ||
1270 | 1262 | ||
1271 | // Legacy form of invocation that passes around a bare data array. | 1263 | // Legacy form of invocation that passes around a bare data array. |
1272 | // Just ignore what was passed and use the real terrain info that is part of the scene. | 1264 | // Just ignore what was passed and use the real terrain info that is part of the scene. |
1273 | // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI, | 1265 | // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI, |
1274 | // there is a special form for specifying multiple terrain patches to send. | 1266 | // there is a special form for specifying multiple terrain patches to send. |
1275 | // The form is to pass 'px' as negative the number of patches to send and to | 1267 | // The form is to pass 'px' as negative the number of patches to send and to |
1276 | // pass the float array as pairs of patch X and Y coordinates. So, passing 'px' | 1268 | // pass the float array as pairs of patch X and Y coordinates. So, passing 'px' |
@@ -1316,6 +1308,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1316 | } | 1308 | } |
1317 | 1309 | ||
1318 | /// <summary> | 1310 | /// <summary> |
1311 | |||
1319 | /// Sends a terrain packet for the point specified. | 1312 | /// Sends a terrain packet for the point specified. |
1320 | /// This is a legacy call that has refarbed the terrain into a flat map of floats. | 1313 | /// This is a legacy call that has refarbed the terrain into a flat map of floats. |
1321 | /// We just use the terrain from the region we know about. | 1314 | /// We just use the terrain from the region we know about. |
@@ -1334,32 +1327,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1334 | { | 1327 | { |
1335 | try | 1328 | try |
1336 | { | 1329 | { |
1337 | /* test code using the terrain compressor in libOpenMetaverse | 1330 | byte landPacketType; |
1338 | int[] patchInd = new int[1]; | 1331 | if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) |
1339 | patchInd[0] = px + (py * Constants.TerrainPatchSize); | 1332 | landPacketType = (byte)TerrainPatch.LayerType.LandExtended; |
1340 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(terrData.GetFloatsSerialized(), patchInd); | 1333 | else |
1341 | */ | 1334 | landPacketType = (byte)TerrainPatch.LayerType.Land; |
1342 | // Many, many patches could have been passed to us. Since the patches will be compressed | ||
1343 | // into variable sized blocks, we cannot pre-compute how many will fit into one | ||
1344 | // packet. While some fancy packing algorithm is possible, 4 seems to always fit. | ||
1345 | int PatchesAssumedToFit = 4; | ||
1346 | for (int pcnt = 0; pcnt < px.Length; pcnt += PatchesAssumedToFit) | ||
1347 | { | ||
1348 | int remaining = Math.Min(px.Length - pcnt, PatchesAssumedToFit); | ||
1349 | int[] xPatches = new int[remaining]; | ||
1350 | int[] yPatches = new int[remaining]; | ||
1351 | for (int ii = 0; ii < remaining; ii++) | ||
1352 | { | ||
1353 | xPatches[ii] = px[pcnt + ii]; | ||
1354 | yPatches[ii] = py[pcnt + ii]; | ||
1355 | } | ||
1356 | LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, xPatches, yPatches); | ||
1357 | // DebugSendingPatches("SendLayerDataInternal", xPatches, yPatches); | ||
1358 | |||
1359 | SendTheLayerPacket(layerpack); | ||
1360 | } | ||
1361 | // LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, px, py); | ||
1362 | 1335 | ||
1336 | List<LayerDataPacket> packets = OpenSimTerrainCompressor.CreateLayerDataPackets(terrData, px, py, landPacketType); | ||
1337 | foreach(LayerDataPacket pkt in packets) | ||
1338 | OutPacket(pkt, ThrottleOutPacketType.Land); | ||
1363 | } | 1339 | } |
1364 | catch (Exception e) | 1340 | catch (Exception e) |
1365 | { | 1341 | { |
@@ -1367,110 +1343,125 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1367 | } | 1343 | } |
1368 | } | 1344 | } |
1369 | 1345 | ||
1370 | // When a user edits the terrain, so much data is sent, the data queues up fast and presents a | ||
1371 | // sub optimal editing experience. To alleviate this issue, when the user edits the terrain, we | ||
1372 | // start skipping the queues until they're done editing the terrain. We also make them | ||
1373 | // unreliable because it's extremely likely that multiple packets will be sent for a terrain patch | ||
1374 | // area invalidating previous packets for that area. | ||
1375 | 1346 | ||
1376 | // It's possible for an editing user to flood themselves with edited packets but the majority | 1347 | // wind caching |
1377 | // of use cases are such that only a tiny percentage of users will be editing the terrain. | 1348 | private static Dictionary<ulong,int> lastWindVersion = new Dictionary<ulong,int>(); |
1378 | // Other, non-editing users will see the edits much slower. | 1349 | private static Dictionary<ulong,List<LayerDataPacket>> lastWindPackets = |
1379 | 1350 | new Dictionary<ulong,List<LayerDataPacket>>(); | |
1380 | // One last note on this topic, by the time users are going to be editing the terrain, it's | ||
1381 | // extremely likely that the sim will have rezzed already and therefore this is not likely going | ||
1382 | // to cause any additional issues with lost packets, objects or terrain patches. | ||
1383 | 1351 | ||
1384 | // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we | ||
1385 | // only have one cache miss. | ||
1386 | private void SendTheLayerPacket(LayerDataPacket layerpack) | ||
1387 | { | ||
1388 | if (m_justEditedTerrain) | ||
1389 | { | ||
1390 | layerpack.Header.Reliable = false; | ||
1391 | OutPacket(layerpack, ThrottleOutPacketType.Unknown ); | ||
1392 | } | ||
1393 | else | ||
1394 | { | ||
1395 | layerpack.Header.Reliable = true; | ||
1396 | OutPacket(layerpack, ThrottleOutPacketType.Land); | ||
1397 | } | ||
1398 | } | ||
1399 | 1352 | ||
1400 | /// <summary> | 1353 | /// <summary> |
1401 | /// Send the wind matrix to the client | 1354 | /// Send the wind matrix to the client |
1402 | /// </summary> | 1355 | /// </summary> |
1403 | /// <param name="windSpeeds">16x16 array of wind speeds</param> | 1356 | /// <param name="windSpeeds">16x16 array of wind speeds</param> |
1404 | public virtual void SendWindData(Vector2[] windSpeeds) | 1357 | public virtual void SendWindData(int version, Vector2[] windSpeeds) |
1405 | { | ||
1406 | Util.FireAndForget(DoSendWindData, windSpeeds, "LLClientView.SendWindData"); | ||
1407 | } | ||
1408 | |||
1409 | /// <summary> | ||
1410 | /// Send the cloud matrix to the client | ||
1411 | /// </summary> | ||
1412 | /// <param name="windSpeeds">16x16 array of cloud densities</param> | ||
1413 | public virtual void SendCloudData(float[] cloudDensity) | ||
1414 | { | ||
1415 | Util.FireAndForget(DoSendCloudData, cloudDensity, "LLClientView.SendCloudData"); | ||
1416 | } | ||
1417 | |||
1418 | /// <summary> | ||
1419 | /// Send wind layer information to the client. | ||
1420 | /// </summary> | ||
1421 | /// <param name="o"></param> | ||
1422 | private void DoSendWindData(object o) | ||
1423 | { | 1358 | { |
1424 | Vector2[] windSpeeds = (Vector2[])o; | 1359 | // Vector2[] windSpeeds = (Vector2[])o; |
1425 | TerrainPatch[] patches = new TerrainPatch[2]; | ||
1426 | patches[0] = new TerrainPatch { Data = new float[16 * 16] }; | ||
1427 | patches[1] = new TerrainPatch { Data = new float[16 * 16] }; | ||
1428 | 1360 | ||
1429 | for (int x = 0; x < 16 * 16; x++) | 1361 | ulong handle = this.Scene.RegionInfo.RegionHandle; |
1362 | bool isNewData; | ||
1363 | lock(lastWindPackets) | ||
1430 | { | 1364 | { |
1431 | patches[0].Data[x] = windSpeeds[x].X; | 1365 | if(!lastWindVersion.ContainsKey(handle) || |
1432 | patches[1].Data[x] = windSpeeds[x].Y; | 1366 | !lastWindPackets.ContainsKey(handle)) |
1367 | { | ||
1368 | lastWindVersion[handle] = 0; | ||
1369 | lastWindPackets[handle] = new List<LayerDataPacket>(); | ||
1370 | isNewData = true; | ||
1371 | } | ||
1372 | else | ||
1373 | isNewData = lastWindVersion[handle] != version; | ||
1433 | } | 1374 | } |
1434 | 1375 | ||
1435 | byte layerType = (byte)TerrainPatch.LayerType.Wind; | 1376 | if(isNewData) |
1436 | if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize) | 1377 | { |
1437 | layerType = (byte)TerrainPatch.LayerType.WindExtended; | 1378 | TerrainPatch[] patches = new TerrainPatch[2]; |
1379 | patches[0] = new TerrainPatch { Data = new float[16 * 16] }; | ||
1380 | patches[1] = new TerrainPatch { Data = new float[16 * 16] }; | ||
1381 | |||
1382 | for (int x = 0; x < 16 * 16; x++) | ||
1383 | { | ||
1384 | patches[0].Data[x] = windSpeeds[x].X; | ||
1385 | patches[1].Data[x] = windSpeeds[x].Y; | ||
1386 | } | ||
1387 | |||
1388 | // neither we or viewers have extended wind | ||
1389 | byte layerType = (byte)TerrainPatch.LayerType.Wind; | ||
1390 | |||
1391 | LayerDataPacket layerpack = | ||
1392 | OpenSimTerrainCompressor.CreateLayerDataPacketStandardSize( | ||
1393 | patches, layerType); | ||
1394 | layerpack.Header.Zerocoded = true; | ||
1395 | lock(lastWindPackets) | ||
1396 | { | ||
1397 | lastWindPackets[handle].Clear(); | ||
1398 | lastWindPackets[handle].Add(layerpack); | ||
1399 | lastWindVersion[handle] = version; | ||
1400 | } | ||
1401 | } | ||
1438 | 1402 | ||
1439 | // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType); | 1403 | lock(lastWindPackets) |
1440 | LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType, | 1404 | foreach(LayerDataPacket pkt in lastWindPackets[handle]) |
1441 | (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY); | 1405 | OutPacket(pkt, ThrottleOutPacketType.Wind); |
1442 | layerpack.Header.Zerocoded = true; | ||
1443 | OutPacket(layerpack, ThrottleOutPacketType.Wind); | ||
1444 | } | 1406 | } |
1445 | 1407 | ||
1408 | // cloud caching | ||
1409 | private static Dictionary<ulong,int> lastCloudVersion = new Dictionary<ulong,int>(); | ||
1410 | private static Dictionary<ulong,List<LayerDataPacket>> lastCloudPackets = | ||
1411 | new Dictionary<ulong,List<LayerDataPacket>>(); | ||
1412 | |||
1446 | /// <summary> | 1413 | /// <summary> |
1447 | /// Send cloud layer information to the client. | 1414 | /// Send the cloud matrix to the client |
1448 | /// </summary> | 1415 | /// </summary> |
1449 | /// <param name="o"></param> | 1416 | /// <param name="windSpeeds">16x16 array of cloud densities</param> |
1450 | private void DoSendCloudData(object o) | 1417 | public virtual void SendCloudData(int version, float[] cloudDensity) |
1451 | { | 1418 | { |
1452 | float[] cloudCover = (float[])o; | 1419 | ulong handle = this.Scene.RegionInfo.RegionHandle; |
1453 | TerrainPatch[] patches = new TerrainPatch[1]; | 1420 | bool isNewData; |
1454 | patches[0] = new TerrainPatch(); | 1421 | lock(lastWindPackets) |
1455 | patches[0].Data = new float[16 * 16]; | ||
1456 | |||
1457 | for (int y = 0; y < 16; y++) | ||
1458 | { | 1422 | { |
1459 | for (int x = 0; x < 16; x++) | 1423 | if(!lastCloudVersion.ContainsKey(handle) || |
1424 | !lastCloudPackets.ContainsKey(handle)) | ||
1460 | { | 1425 | { |
1461 | patches[0].Data[y * 16 + x] = cloudCover[y * 16 + x]; | 1426 | lastCloudVersion[handle] = 0; |
1427 | lastCloudPackets[handle] = new List<LayerDataPacket>(); | ||
1428 | isNewData = true; | ||
1462 | } | 1429 | } |
1430 | else | ||
1431 | isNewData = lastCloudVersion[handle] != version; | ||
1463 | } | 1432 | } |
1464 | 1433 | ||
1465 | byte layerType = (byte)TerrainPatch.LayerType.Cloud; | 1434 | if(isNewData) |
1466 | if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize) | 1435 | { |
1467 | layerType = (byte)TerrainPatch.LayerType.CloudExtended; | 1436 | TerrainPatch[] patches = new TerrainPatch[1]; |
1437 | patches[0] = new TerrainPatch(); | ||
1438 | patches[0].Data = new float[16 * 16]; | ||
1439 | |||
1440 | for (int y = 0; y < 16; y++) | ||
1441 | { | ||
1442 | for (int x = 0; x < 16; x++) | ||
1443 | { | ||
1444 | patches[0].Data[y * 16 + x] = cloudDensity[y * 16 + x]; | ||
1445 | } | ||
1446 | } | ||
1447 | // neither we or viewers have extended clouds | ||
1448 | byte layerType = (byte)TerrainPatch.LayerType.Cloud; | ||
1449 | |||
1450 | LayerDataPacket layerpack = | ||
1451 | OpenSimTerrainCompressor.CreateLayerDataPacketStandardSize( | ||
1452 | patches, layerType); | ||
1453 | layerpack.Header.Zerocoded = true; | ||
1454 | lock(lastCloudPackets) | ||
1455 | { | ||
1456 | lastCloudPackets[handle].Clear(); | ||
1457 | lastCloudPackets[handle].Add(layerpack); | ||
1458 | lastCloudVersion[handle] = version; | ||
1459 | } | ||
1460 | } | ||
1468 | 1461 | ||
1469 | // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType); | 1462 | lock(lastCloudPackets) |
1470 | LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType, | 1463 | foreach(LayerDataPacket pkt in lastCloudPackets[handle]) |
1471 | (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY); | 1464 | OutPacket(pkt, ThrottleOutPacketType.Cloud); |
1472 | layerpack.Header.Zerocoded = true; | ||
1473 | OutPacket(layerpack, ThrottleOutPacketType.Cloud); | ||
1474 | } | 1465 | } |
1475 | 1466 | ||
1476 | /// <summary> | 1467 | /// <summary> |
@@ -1735,45 +1726,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1735 | pc.PingID.OldestUnacked = 0; | 1726 | pc.PingID.OldestUnacked = 0; |
1736 | 1727 | ||
1737 | OutPacket(pc, ThrottleOutPacketType.Unknown); | 1728 | OutPacket(pc, ThrottleOutPacketType.Unknown); |
1729 | UDPClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount(); | ||
1738 | } | 1730 | } |
1739 | 1731 | ||
1740 | public void SendKillObject(List<uint> localIDs) | 1732 | public void SendKillObject(List<uint> localIDs) |
1741 | { | 1733 | { |
1742 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); | 1734 | // foreach (uint id in localIDs) |
1735 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); | ||
1736 | |||
1737 | // remove pending entities to reduce looping chances. | ||
1738 | lock (m_entityProps.SyncRoot) | ||
1739 | m_entityProps.Remove(localIDs); | ||
1740 | lock (m_entityUpdates.SyncRoot) | ||
1741 | m_entityUpdates.Remove(localIDs); | ||
1743 | 1742 | ||
1744 | KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); | 1743 | KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); |
1745 | // TODO: don't create new blocks if recycling an old packet | 1744 | |
1746 | kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count]; | 1745 | int perpacket = localIDs.Count; |
1746 | if(perpacket > 200) | ||
1747 | perpacket = 200; | ||
1748 | |||
1749 | int nsent = 0; | ||
1750 | |||
1751 | kill.ObjectData = new KillObjectPacket.ObjectDataBlock[perpacket]; | ||
1747 | for (int i = 0 ; i < localIDs.Count ; i++ ) | 1752 | for (int i = 0 ; i < localIDs.Count ; i++ ) |
1748 | { | 1753 | { |
1749 | kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock(); | 1754 | kill.ObjectData[nsent] = new KillObjectPacket.ObjectDataBlock(); |
1750 | kill.ObjectData[i].ID = localIDs[i]; | 1755 | kill.ObjectData[nsent].ID = localIDs[i]; |
1751 | } | ||
1752 | kill.Header.Reliable = true; | ||
1753 | kill.Header.Zerocoded = true; | ||
1754 | 1756 | ||
1755 | if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null) | 1757 | if(++nsent >= 200) |
1756 | { | ||
1757 | OutPacket(kill, ThrottleOutPacketType.Task); | ||
1758 | } | ||
1759 | else | ||
1760 | { | ||
1761 | // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race | ||
1762 | // condition where a kill can be processed before an out-of-date update for the same object. | ||
1763 | // ProcessEntityUpdates() also takes the m_killRecord lock. | ||
1764 | lock (m_killRecord) | ||
1765 | { | 1758 | { |
1766 | foreach (uint localID in localIDs) | 1759 | kill.Header.Reliable = true; |
1767 | m_killRecord.Add(localID); | 1760 | kill.Header.Zerocoded = true; |
1768 | |||
1769 | // The throttle queue used here must match that being used for updates. Otherwise, there is a | ||
1770 | // chance that a kill packet put on a separate queue will be sent to the client before an existing | ||
1771 | // update packet on another queue. Receiving updates after kills results in unowned and undeletable | ||
1772 | // scene objects in a viewer until that viewer is relogged in. | ||
1773 | OutPacket(kill, ThrottleOutPacketType.Task); | 1761 | OutPacket(kill, ThrottleOutPacketType.Task); |
1762 | |||
1763 | perpacket = localIDs.Count - i - 1; | ||
1764 | if(perpacket == 0) | ||
1765 | break; | ||
1766 | if(perpacket > 200) | ||
1767 | perpacket = 200; | ||
1768 | |||
1769 | kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); | ||
1770 | kill.ObjectData = new KillObjectPacket.ObjectDataBlock[perpacket]; | ||
1771 | nsent = 0; | ||
1774 | } | 1772 | } |
1775 | } | 1773 | } |
1776 | } | 1774 | |
1775 | if(nsent != 0) | ||
1776 | { | ||
1777 | kill.Header.Reliable = true; | ||
1778 | kill.Header.Zerocoded = true; | ||
1779 | OutPacket(kill, ThrottleOutPacketType.Task); | ||
1780 | } | ||
1781 | } | ||
1777 | 1782 | ||
1778 | /// <summary> | 1783 | /// <summary> |
1779 | /// Send information about the items contained in a folder to the client. | 1784 | /// Send information about the items contained in a folder to the client. |
@@ -1895,7 +1900,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1895 | newBlock.CreationDate = item.CreationDate; | 1900 | newBlock.CreationDate = item.CreationDate; |
1896 | newBlock.SalePrice = item.SalePrice; | 1901 | newBlock.SalePrice = item.SalePrice; |
1897 | newBlock.SaleType = item.SaleType; | 1902 | newBlock.SaleType = item.SaleType; |
1898 | newBlock.Flags = item.Flags; | 1903 | newBlock.Flags = item.Flags & 0x2000ff; |
1899 | 1904 | ||
1900 | newBlock.CRC = | 1905 | newBlock.CRC = |
1901 | Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType, | 1906 | Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType, |
@@ -2151,7 +2156,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2151 | itemBlock.GroupID = item.GroupID; | 2156 | itemBlock.GroupID = item.GroupID; |
2152 | itemBlock.GroupOwned = item.GroupOwned; | 2157 | itemBlock.GroupOwned = item.GroupOwned; |
2153 | itemBlock.GroupMask = item.GroupPermissions; | 2158 | itemBlock.GroupMask = item.GroupPermissions; |
2154 | itemBlock.Flags = item.Flags; | 2159 | itemBlock.Flags = item.Flags & 0x2000ff; |
2155 | itemBlock.SalePrice = item.SalePrice; | 2160 | itemBlock.SalePrice = item.SalePrice; |
2156 | itemBlock.SaleType = item.SaleType; | 2161 | itemBlock.SaleType = item.SaleType; |
2157 | itemBlock.CreationDate = item.CreationDate; | 2162 | itemBlock.CreationDate = item.CreationDate; |
@@ -2218,7 +2223,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2218 | bulkUpdate.ItemData[0].GroupID = item.GroupID; | 2223 | bulkUpdate.ItemData[0].GroupID = item.GroupID; |
2219 | bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; | 2224 | bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; |
2220 | bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions; | 2225 | bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions; |
2221 | bulkUpdate.ItemData[0].Flags = item.Flags; | 2226 | bulkUpdate.ItemData[0].Flags = item.Flags & 0x2000ff; |
2222 | bulkUpdate.ItemData[0].SalePrice = item.SalePrice; | 2227 | bulkUpdate.ItemData[0].SalePrice = item.SalePrice; |
2223 | bulkUpdate.ItemData[0].SaleType = item.SaleType; | 2228 | bulkUpdate.ItemData[0].SaleType = item.SaleType; |
2224 | 2229 | ||
@@ -2234,9 +2239,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2234 | OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); | 2239 | OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); |
2235 | } | 2240 | } |
2236 | 2241 | ||
2237 | /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see> | ||
2238 | public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) | 2242 | public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) |
2239 | { | 2243 | { |
2244 | SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId); | ||
2245 | } | ||
2246 | |||
2247 | /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see> | ||
2248 | public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId) | ||
2249 | { | ||
2240 | const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; | 2250 | const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; |
2241 | 2251 | ||
2242 | UpdateCreateInventoryItemPacket InventoryReply | 2252 | UpdateCreateInventoryItemPacket InventoryReply |
@@ -2246,6 +2256,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2246 | // TODO: don't create new blocks if recycling an old packet | 2256 | // TODO: don't create new blocks if recycling an old packet |
2247 | InventoryReply.AgentData.AgentID = AgentId; | 2257 | InventoryReply.AgentData.AgentID = AgentId; |
2248 | InventoryReply.AgentData.SimApproved = true; | 2258 | InventoryReply.AgentData.SimApproved = true; |
2259 | InventoryReply.AgentData.TransactionID = transactionID; | ||
2249 | InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; | 2260 | InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; |
2250 | InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); | 2261 | InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); |
2251 | InventoryReply.InventoryData[0].ItemID = Item.ID; | 2262 | InventoryReply.InventoryData[0].ItemID = Item.ID; |
@@ -2266,7 +2277,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2266 | InventoryReply.InventoryData[0].GroupID = Item.GroupID; | 2277 | InventoryReply.InventoryData[0].GroupID = Item.GroupID; |
2267 | InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; | 2278 | InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; |
2268 | InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions; | 2279 | InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions; |
2269 | InventoryReply.InventoryData[0].Flags = Item.Flags; | 2280 | InventoryReply.InventoryData[0].Flags = Item.Flags & 0x2000ff; |
2270 | InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; | 2281 | InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; |
2271 | InventoryReply.InventoryData[0].SaleType = Item.SaleType; | 2282 | InventoryReply.InventoryData[0].SaleType = Item.SaleType; |
2272 | InventoryReply.InventoryData[0].CreationDate = Item.CreationDate; | 2283 | InventoryReply.InventoryData[0].CreationDate = Item.CreationDate; |
@@ -2296,11 +2307,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2296 | OutPacket(remove, ThrottleOutPacketType.Asset); | 2307 | OutPacket(remove, ThrottleOutPacketType.Asset); |
2297 | } | 2308 | } |
2298 | 2309 | ||
2310 | /* | ||
2311 | private uint adjustControls(int input) | ||
2312 | { | ||
2313 | uint ret = (uint)input; | ||
2314 | uint masked = ret & 0x0f; | ||
2315 | masked <<= 19; | ||
2316 | ret |= masked; | ||
2317 | return ret; | ||
2318 | } | ||
2319 | */ | ||
2320 | |||
2299 | public void SendTakeControls(int controls, bool passToAgent, bool TakeControls) | 2321 | public void SendTakeControls(int controls, bool passToAgent, bool TakeControls) |
2300 | { | 2322 | { |
2301 | ScriptControlChangePacket scriptcontrol = (ScriptControlChangePacket)PacketPool.Instance.GetPacket(PacketType.ScriptControlChange); | 2323 | ScriptControlChangePacket scriptcontrol = (ScriptControlChangePacket)PacketPool.Instance.GetPacket(PacketType.ScriptControlChange); |
2302 | ScriptControlChangePacket.DataBlock[] data = new ScriptControlChangePacket.DataBlock[1]; | 2324 | ScriptControlChangePacket.DataBlock[] data = new ScriptControlChangePacket.DataBlock[1]; |
2303 | ScriptControlChangePacket.DataBlock ddata = new ScriptControlChangePacket.DataBlock(); | 2325 | ScriptControlChangePacket.DataBlock ddata = new ScriptControlChangePacket.DataBlock(); |
2326 | // ddata.Controls = adjustControls(controls); | ||
2304 | ddata.Controls = (uint)controls; | 2327 | ddata.Controls = (uint)controls; |
2305 | ddata.PassToAgent = passToAgent; | 2328 | ddata.PassToAgent = passToAgent; |
2306 | ddata.TakeControls = TakeControls; | 2329 | ddata.TakeControls = TakeControls; |
@@ -2315,16 +2338,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2315 | replytask.InventoryData.TaskID = taskID; | 2338 | replytask.InventoryData.TaskID = taskID; |
2316 | replytask.InventoryData.Serial = serial; | 2339 | replytask.InventoryData.Serial = serial; |
2317 | replytask.InventoryData.Filename = fileName; | 2340 | replytask.InventoryData.Filename = fileName; |
2341 | // OutPacket(replytask, ThrottleOutPacketType.Task); | ||
2318 | OutPacket(replytask, ThrottleOutPacketType.Asset); | 2342 | OutPacket(replytask, ThrottleOutPacketType.Asset); |
2319 | } | 2343 | } |
2320 | 2344 | ||
2321 | public void SendXferPacket(ulong xferID, uint packet, byte[] data) | 2345 | public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory) |
2322 | { | 2346 | { |
2347 | ThrottleOutPacketType type = ThrottleOutPacketType.Asset; | ||
2348 | // if (isTaskInventory) | ||
2349 | // type = ThrottleOutPacketType.Task; | ||
2350 | |||
2323 | SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); | 2351 | SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); |
2324 | sendXfer.XferID.ID = xferID; | 2352 | sendXfer.XferID.ID = xferID; |
2325 | sendXfer.XferID.Packet = packet; | 2353 | sendXfer.XferID.Packet = packet; |
2326 | sendXfer.DataPacket.Data = data; | 2354 | sendXfer.DataPacket.Data = data; |
2327 | OutPacket(sendXfer, ThrottleOutPacketType.Asset); | 2355 | OutPacket(sendXfer, type); |
2328 | } | 2356 | } |
2329 | 2357 | ||
2330 | public void SendAbortXferPacket(ulong xferID) | 2358 | public void SendAbortXferPacket(ulong xferID) |
@@ -2415,6 +2443,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2415 | OutPacket(alertPack, ThrottleOutPacketType.Task); | 2443 | OutPacket(alertPack, ThrottleOutPacketType.Task); |
2416 | } | 2444 | } |
2417 | 2445 | ||
2446 | public void SendAlertMessage(string message, string info) | ||
2447 | { | ||
2448 | AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage); | ||
2449 | alertPack.AlertData = new AlertMessagePacket.AlertDataBlock(); | ||
2450 | alertPack.AlertData.Message = Util.StringToBytes256(message); | ||
2451 | alertPack.AlertInfo = new AlertMessagePacket.AlertInfoBlock[1]; | ||
2452 | alertPack.AlertInfo[0] = new AlertMessagePacket.AlertInfoBlock(); | ||
2453 | alertPack.AlertInfo[0].Message = Util.StringToBytes256(info); | ||
2454 | alertPack.AlertInfo[0].ExtraParams = new Byte[0]; | ||
2455 | OutPacket(alertPack, ThrottleOutPacketType.Task); | ||
2456 | } | ||
2457 | |||
2418 | /// <summary> | 2458 | /// <summary> |
2419 | /// Send an agent alert message to the client. | 2459 | /// Send an agent alert message to the client. |
2420 | /// </summary> | 2460 | /// </summary> |
@@ -2471,7 +2511,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2471 | // this is the username of the *owner* | 2511 | // this is the username of the *owner* |
2472 | dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName); | 2512 | dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName); |
2473 | dialog.Data.LastName = Util.StringToBytes256(ownerLastName); | 2513 | dialog.Data.LastName = Util.StringToBytes256(ownerLastName); |
2474 | dialog.Data.Message = Util.StringToBytes1024(msg); | 2514 | dialog.Data.Message = Util.StringToBytes(msg,512); |
2475 | dialog.Data.ImageID = textureID; | 2515 | dialog.Data.ImageID = textureID; |
2476 | dialog.Data.ChatChannel = ch; | 2516 | dialog.Data.ChatChannel = ch; |
2477 | ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length]; | 2517 | ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length]; |
@@ -2514,6 +2554,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2514 | OutPacket(sound, ThrottleOutPacketType.Task); | 2554 | OutPacket(sound, ThrottleOutPacketType.Task); |
2515 | } | 2555 | } |
2516 | 2556 | ||
2557 | public void SendTransferAbort(TransferRequestPacket transferRequest) | ||
2558 | { | ||
2559 | TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort); | ||
2560 | abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID; | ||
2561 | abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType; | ||
2562 | m_log.Debug("[Assets] Aborting transfer; asset request failed"); | ||
2563 | OutPacket(abort, ThrottleOutPacketType.Task); | ||
2564 | } | ||
2565 | |||
2517 | public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) | 2566 | public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) |
2518 | { | 2567 | { |
2519 | SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); | 2568 | SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); |
@@ -2632,7 +2681,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2632 | OutPacket(packet, ThrottleOutPacketType.Task); | 2681 | OutPacket(packet, ThrottleOutPacketType.Task); |
2633 | } | 2682 | } |
2634 | 2683 | ||
2635 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, | 2684 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType, |
2636 | string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, | 2685 | string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, |
2637 | UUID partnerID) | 2686 | UUID partnerID) |
2638 | { | 2687 | { |
@@ -2644,7 +2693,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2644 | else | 2693 | else |
2645 | avatarReply.PropertiesData.AboutText = Utils.EmptyBytes; | 2694 | avatarReply.PropertiesData.AboutText = Utils.EmptyBytes; |
2646 | avatarReply.PropertiesData.BornOn = Util.StringToBytes256(bornOn); | 2695 | avatarReply.PropertiesData.BornOn = Util.StringToBytes256(bornOn); |
2647 | avatarReply.PropertiesData.CharterMember = charterMember; | 2696 | avatarReply.PropertiesData.CharterMember = membershipType; |
2648 | if (flAbout != null) | 2697 | if (flAbout != null) |
2649 | avatarReply.PropertiesData.FLAboutText = Util.StringToBytes256(flAbout); | 2698 | avatarReply.PropertiesData.FLAboutText = Util.StringToBytes256(flAbout); |
2650 | else | 2699 | else |
@@ -2730,8 +2779,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2730 | OutPacket(offp, ThrottleOutPacketType.Task); | 2779 | OutPacket(offp, ThrottleOutPacketType.Task); |
2731 | } | 2780 | } |
2732 | 2781 | ||
2733 | public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, Quaternion SitOrientation, bool autopilot, | 2782 | public void SendFindAgent(UUID HunterID, UUID PreyID, double GlobalX, double GlobalY) |
2734 | Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) | 2783 | { |
2784 | FindAgentPacket fap = new FindAgentPacket(); | ||
2785 | fap.AgentBlock.Hunter = HunterID; | ||
2786 | fap.AgentBlock.Prey = PreyID; | ||
2787 | fap.AgentBlock.SpaceIP = 0; | ||
2788 | |||
2789 | fap.LocationBlock = new FindAgentPacket.LocationBlockBlock[1]; | ||
2790 | fap.LocationBlock[0] = new FindAgentPacket.LocationBlockBlock(); | ||
2791 | fap.LocationBlock[0].GlobalX = GlobalX; | ||
2792 | fap.LocationBlock[0].GlobalY = GlobalY; | ||
2793 | |||
2794 | OutPacket(fap, ThrottleOutPacketType.Task); | ||
2795 | } | ||
2796 | |||
2797 | public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, | ||
2798 | Quaternion SitOrientation, bool autopilot, | ||
2799 | Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) | ||
2735 | { | 2800 | { |
2736 | AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); | 2801 | AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); |
2737 | avatarSitResponse.SitObject.ID = TargetID; | 2802 | avatarSitResponse.SitObject.ID = TargetID; |
@@ -2763,46 +2828,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2763 | 2828 | ||
2764 | public void SendGroupMembership(GroupMembershipData[] GroupMembership) | 2829 | public void SendGroupMembership(GroupMembershipData[] GroupMembership) |
2765 | { | 2830 | { |
2766 | m_groupPowers.Clear(); | ||
2767 | 2831 | ||
2768 | AgentGroupDataUpdatePacket Groupupdate = new AgentGroupDataUpdatePacket(); | 2832 | UpdateGroupMembership(GroupMembership); |
2769 | AgentGroupDataUpdatePacket.GroupDataBlock[] Groups = new AgentGroupDataUpdatePacket.GroupDataBlock[GroupMembership.Length]; | 2833 | SendAgentGroupDataUpdate(AgentId,GroupMembership); |
2770 | for (int i = 0; i < GroupMembership.Length; i++) | 2834 | } |
2771 | { | ||
2772 | m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers; | ||
2773 | 2835 | ||
2774 | AgentGroupDataUpdatePacket.GroupDataBlock Group = new AgentGroupDataUpdatePacket.GroupDataBlock(); | 2836 | public void SendSelectedPartsProprieties(List<ISceneEntity> parts) |
2775 | Group.AcceptNotices = GroupMembership[i].AcceptNotices; | 2837 | { |
2776 | Group.Contribution = GroupMembership[i].Contribution; | 2838 | /* not in use |
2777 | Group.GroupID = GroupMembership[i].GroupID; | 2839 | // udp part |
2778 | Group.GroupInsigniaID = GroupMembership[i].GroupPicture; | 2840 | ObjectPropertiesPacket packet = |
2779 | Group.GroupName = Util.StringToBytes256(GroupMembership[i].GroupName); | 2841 | (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); |
2780 | Group.GroupPowers = GroupMembership[i].GroupPowers; | 2842 | ObjectPropertiesPacket.ObjectDataBlock[] ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[parts.Count]; |
2781 | Groups[i] = Group; | ||
2782 | 2843 | ||
2844 | int i = 0; | ||
2845 | foreach(SceneObjectPart sop in parts) | ||
2846 | ObjectData[i++] = CreateObjectPropertiesBlock(sop); | ||
2783 | 2847 | ||
2784 | } | 2848 | packet.ObjectData = ObjectData; |
2785 | Groupupdate.GroupData = Groups; | 2849 | packet.Header.Zerocoded = true; |
2786 | Groupupdate.AgentData = new AgentGroupDataUpdatePacket.AgentDataBlock(); | 2850 | // udp send splits this mega packets correctly |
2787 | Groupupdate.AgentData.AgentID = AgentId; | 2851 | // mb later will avoid that to reduce gc stress |
2788 | OutPacket(Groupupdate, ThrottleOutPacketType.Task); | 2852 | OutPacket(packet, ThrottleOutPacketType.Task, true); |
2789 | 2853 | ||
2790 | try | 2854 | // caps physics part |
2791 | { | 2855 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); |
2792 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); | 2856 | if(eq == null) |
2793 | if (eq != null) | 2857 | return; |
2794 | { | 2858 | |
2795 | eq.GroupMembership(Groupupdate, this.AgentId); | 2859 | OSDArray array = new OSDArray(); |
2796 | } | 2860 | foreach(SceneObjectPart sop in parts) |
2797 | } | ||
2798 | catch (Exception ex) | ||
2799 | { | 2861 | { |
2800 | m_log.Error("Unable to send group membership data via eventqueue - exception: " + ex.ToString()); | 2862 | OSDMap physinfo = new OSDMap(6); |
2801 | m_log.Warn("sending group membership data via UDP"); | 2863 | physinfo["LocalID"] = sop.LocalId; |
2802 | OutPacket(Groupupdate, ThrottleOutPacketType.Task); | 2864 | physinfo["Density"] = sop.Density; |
2865 | physinfo["Friction"] = sop.Friction; | ||
2866 | physinfo["GravityMultiplier"] = sop.GravityModifier; | ||
2867 | physinfo["Restitution"] = sop.Restitution; | ||
2868 | physinfo["PhysicsShapeType"] = (int)sop.PhysicsShapeType; | ||
2869 | array.Add(physinfo); | ||
2803 | } | 2870 | } |
2871 | |||
2872 | OSDMap llsdBody = new OSDMap(1); | ||
2873 | llsdBody.Add("ObjectData", array); | ||
2874 | |||
2875 | eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId); | ||
2876 | */ | ||
2804 | } | 2877 | } |
2805 | 2878 | ||
2879 | |||
2806 | public void SendPartPhysicsProprieties(ISceneEntity entity) | 2880 | public void SendPartPhysicsProprieties(ISceneEntity entity) |
2807 | { | 2881 | { |
2808 | SceneObjectPart part = (SceneObjectPart)entity; | 2882 | SceneObjectPart part = (SceneObjectPart)entity; |
@@ -2819,6 +2893,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2819 | float friction = part.Friction; | 2893 | float friction = part.Friction; |
2820 | float bounce = part.Restitution; | 2894 | float bounce = part.Restitution; |
2821 | float gravmod = part.GravityModifier; | 2895 | float gravmod = part.GravityModifier; |
2896 | |||
2822 | eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); | 2897 | eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); |
2823 | } | 2898 | } |
2824 | } | 2899 | } |
@@ -2826,7 +2901,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2826 | { | 2901 | { |
2827 | m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString()); | 2902 | m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString()); |
2828 | } | 2903 | } |
2829 | part.UpdatePhysRequired = false; | ||
2830 | } | 2904 | } |
2831 | } | 2905 | } |
2832 | 2906 | ||
@@ -2883,6 +2957,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2883 | 2957 | ||
2884 | public void SendAsset(AssetRequestToClient req) | 2958 | public void SendAsset(AssetRequestToClient req) |
2885 | { | 2959 | { |
2960 | if (req.AssetInf == null) | ||
2961 | { | ||
2962 | m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset is null", | ||
2963 | LogHeader); | ||
2964 | return; | ||
2965 | } | ||
2966 | |||
2886 | if (req.AssetInf.Data == null) | 2967 | if (req.AssetInf.Data == null) |
2887 | { | 2968 | { |
2888 | m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset data is null", | 2969 | m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset data is null", |
@@ -2890,7 +2971,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2890 | return; | 2971 | return; |
2891 | } | 2972 | } |
2892 | 2973 | ||
2893 | //m_log.Debug("sending asset " + req.RequestAssetID); | 2974 | bool isWearable = false; |
2975 | |||
2976 | isWearable = ((AssetType) req.AssetInf.Type == | ||
2977 | AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing); | ||
2978 | |||
2979 | |||
2980 | //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable); | ||
2981 | |||
2982 | |||
2983 | //if (isWearable) | ||
2984 | // m_log.Debug((AssetType)req.AssetInf.Type); | ||
2985 | |||
2894 | TransferInfoPacket Transfer = new TransferInfoPacket(); | 2986 | TransferInfoPacket Transfer = new TransferInfoPacket(); |
2895 | Transfer.TransferInfo.ChannelType = 2; | 2987 | Transfer.TransferInfo.ChannelType = 2; |
2896 | Transfer.TransferInfo.Status = 0; | 2988 | Transfer.TransferInfo.Status = 0; |
@@ -2912,7 +3004,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2912 | Transfer.TransferInfo.Size = req.AssetInf.Data.Length; | 3004 | Transfer.TransferInfo.Size = req.AssetInf.Data.Length; |
2913 | Transfer.TransferInfo.TransferID = req.TransferRequestID; | 3005 | Transfer.TransferInfo.TransferID = req.TransferRequestID; |
2914 | Transfer.Header.Zerocoded = true; | 3006 | Transfer.Header.Zerocoded = true; |
2915 | OutPacket(Transfer, ThrottleOutPacketType.Asset); | 3007 | OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset); |
2916 | 3008 | ||
2917 | if (req.NumPackets == 1) | 3009 | if (req.NumPackets == 1) |
2918 | { | 3010 | { |
@@ -2923,12 +3015,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2923 | TransferPacket.TransferData.Data = req.AssetInf.Data; | 3015 | TransferPacket.TransferData.Data = req.AssetInf.Data; |
2924 | TransferPacket.TransferData.Status = 1; | 3016 | TransferPacket.TransferData.Status = 1; |
2925 | TransferPacket.Header.Zerocoded = true; | 3017 | TransferPacket.Header.Zerocoded = true; |
2926 | OutPacket(TransferPacket, ThrottleOutPacketType.Asset); | 3018 | OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset); |
2927 | } | 3019 | } |
2928 | else | 3020 | else |
2929 | { | 3021 | { |
2930 | int processedLength = 0; | 3022 | int processedLength = 0; |
2931 | int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; | 3023 | // int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; |
3024 | |||
3025 | int maxChunkSize = (int) MaxTransferBytesPerPacket; | ||
2932 | int packetNumber = 0; | 3026 | int packetNumber = 0; |
2933 | 3027 | ||
2934 | while (processedLength < req.AssetInf.Data.Length) | 3028 | while (processedLength < req.AssetInf.Data.Length) |
@@ -2954,7 +3048,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2954 | TransferPacket.TransferData.Status = 1; | 3048 | TransferPacket.TransferData.Status = 1; |
2955 | } | 3049 | } |
2956 | TransferPacket.Header.Zerocoded = true; | 3050 | TransferPacket.Header.Zerocoded = true; |
2957 | OutPacket(TransferPacket, ThrottleOutPacketType.Asset); | 3051 | OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset); |
2958 | 3052 | ||
2959 | processedLength += chunkSize; | 3053 | processedLength += chunkSize; |
2960 | packetNumber++; | 3054 | packetNumber++; |
@@ -2990,23 +3084,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2990 | 3084 | ||
2991 | public void SendParcelInfo(RegionInfo info, LandData land, UUID parcelID, uint x, uint y) | 3085 | public void SendParcelInfo(RegionInfo info, LandData land, UUID parcelID, uint x, uint y) |
2992 | { | 3086 | { |
2993 | float dwell = 0.0f; | ||
2994 | IDwellModule dwellModule = m_scene.RequestModuleInterface<IDwellModule>(); | ||
2995 | if (dwellModule != null) | ||
2996 | dwell = dwellModule.GetDwell(land.GlobalID); | ||
2997 | ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelInfoReply); | 3087 | ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelInfoReply); |
2998 | reply.AgentData.AgentID = m_agentId; | 3088 | reply.AgentData.AgentID = m_agentId; |
2999 | reply.Data.ParcelID = parcelID; | 3089 | reply.Data.ParcelID = parcelID; |
3000 | reply.Data.OwnerID = land.OwnerID; | 3090 | reply.Data.OwnerID = land.OwnerID; |
3001 | reply.Data.Name = Utils.StringToBytes(land.Name); | 3091 | reply.Data.Name = Utils.StringToBytes(land.Name); |
3002 | reply.Data.Desc = Utils.StringToBytes(land.Description); | 3092 | if (land.Description != null && land.Description != String.Empty) |
3093 | reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length)); | ||
3094 | else | ||
3095 | reply.Data.Desc = new Byte[0]; | ||
3003 | reply.Data.ActualArea = land.Area; | 3096 | reply.Data.ActualArea = land.Area; |
3004 | reply.Data.BillableArea = land.Area; // TODO: what is this? | 3097 | reply.Data.BillableArea = land.Area; // TODO: what is this? |
3005 | 3098 | ||
3006 | // Bit 0: Mature, bit 7: on sale, other bits: no idea | 3099 | reply.Data.Flags = (byte)Util.ConvertAccessLevelToMaturity((byte)info.AccessLevel); |
3007 | reply.Data.Flags = (byte)( | 3100 | if((land.Flags & (uint)ParcelFlags.ForSale) != 0) |
3008 | (info.AccessLevel > 13 ? (1 << 0) : 0) + | 3101 | reply.Data.Flags |= (byte)((1 << 7)); |
3009 | ((land.Flags & (uint)ParcelFlags.ForSale) != 0 ? (1 << 7) : 0)); | ||
3010 | 3102 | ||
3011 | Vector3 pos = land.UserLocation; | 3103 | Vector3 pos = land.UserLocation; |
3012 | if (pos.Equals(Vector3.Zero)) | 3104 | if (pos.Equals(Vector3.Zero)) |
@@ -3018,7 +3110,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3018 | reply.Data.GlobalZ = pos.Z; | 3110 | reply.Data.GlobalZ = pos.Z; |
3019 | reply.Data.SimName = Utils.StringToBytes(info.RegionName); | 3111 | reply.Data.SimName = Utils.StringToBytes(info.RegionName); |
3020 | reply.Data.SnapshotID = land.SnapshotID; | 3112 | reply.Data.SnapshotID = land.SnapshotID; |
3021 | reply.Data.Dwell = dwell; | 3113 | reply.Data.Dwell = land.Dwell; |
3022 | reply.Data.SalePrice = land.SalePrice; | 3114 | reply.Data.SalePrice = land.SalePrice; |
3023 | reply.Data.AuctionID = (int)land.AuctionID; | 3115 | reply.Data.AuctionID = (int)land.AuctionID; |
3024 | 3116 | ||
@@ -3385,7 +3477,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3385 | AgentData.Add(AgentDataMap); | 3477 | AgentData.Add(AgentDataMap); |
3386 | llsd.Add("AgentData", AgentData); | 3478 | llsd.Add("AgentData", AgentData); |
3387 | OSDArray GroupData = new OSDArray(data.Length); | 3479 | OSDArray GroupData = new OSDArray(data.Length); |
3388 | OSDArray NewGroupData = new OSDArray(data.Length); | 3480 | // OSDArray NewGroupData = new OSDArray(data.Length); |
3389 | foreach (GroupMembershipData m in data) | 3481 | foreach (GroupMembershipData m in data) |
3390 | { | 3482 | { |
3391 | OSDMap GroupDataMap = new OSDMap(6); | 3483 | OSDMap GroupDataMap = new OSDMap(6); |
@@ -3396,12 +3488,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3396 | GroupDataMap.Add("GroupID", OSD.FromUUID(m.GroupID)); | 3488 | GroupDataMap.Add("GroupID", OSD.FromUUID(m.GroupID)); |
3397 | GroupDataMap.Add("GroupName", OSD.FromString(m.GroupName)); | 3489 | GroupDataMap.Add("GroupName", OSD.FromString(m.GroupName)); |
3398 | GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(m.GroupPicture)); | 3490 | GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(m.GroupPicture)); |
3399 | NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(m.ListInProfile)); | 3491 | // NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(m.ListInProfile)); |
3400 | GroupData.Add(GroupDataMap); | 3492 | GroupData.Add(GroupDataMap); |
3401 | NewGroupData.Add(NewGroupDataMap); | 3493 | // NewGroupData.Add(NewGroupDataMap); |
3402 | } | 3494 | } |
3403 | llsd.Add("GroupData", GroupData); | 3495 | llsd.Add("GroupData", GroupData); |
3404 | llsd.Add("NewGroupData", NewGroupData); | 3496 | // llsd.Add("NewGroupData", NewGroupData); |
3405 | 3497 | ||
3406 | IEventQueue eq = this.Scene.RequestModuleInterface<IEventQueue>(); | 3498 | IEventQueue eq = this.Scene.RequestModuleInterface<IEventQueue>(); |
3407 | if (eq != null) | 3499 | if (eq != null) |
@@ -3410,6 +3502,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3410 | } | 3502 | } |
3411 | } | 3503 | } |
3412 | 3504 | ||
3505 | public void SendAgentGroupDataUpdate(UUID avatarID, GroupMembershipData[] data) | ||
3506 | { | ||
3507 | if(avatarID != AgentId) | ||
3508 | m_log.Debug("[CLIENT]: SendAgentGroupDataUpdate avatarID != AgentId"); | ||
3509 | |||
3510 | IEventQueue eq = this.Scene.RequestModuleInterface<IEventQueue>(); | ||
3511 | if(eq != null) | ||
3512 | { | ||
3513 | eq.GroupMembershipData(avatarID,data); | ||
3514 | } | ||
3515 | else | ||
3516 | { | ||
3517 | // use UDP if no caps | ||
3518 | AgentGroupDataUpdatePacket Groupupdate = new AgentGroupDataUpdatePacket(); | ||
3519 | AgentGroupDataUpdatePacket.GroupDataBlock[] Groups = new AgentGroupDataUpdatePacket.GroupDataBlock[data.Length]; | ||
3520 | for (int i = 0; i < data.Length; i++) | ||
3521 | { | ||
3522 | AgentGroupDataUpdatePacket.GroupDataBlock Group = new AgentGroupDataUpdatePacket.GroupDataBlock(); | ||
3523 | Group.AcceptNotices = data[i].AcceptNotices; | ||
3524 | Group.Contribution = data[i].Contribution; | ||
3525 | Group.GroupID = data[i].GroupID; | ||
3526 | Group.GroupInsigniaID = data[i].GroupPicture; | ||
3527 | Group.GroupName = Util.StringToBytes256(data[i].GroupName); | ||
3528 | Group.GroupPowers = data[i].GroupPowers; | ||
3529 | Groups[i] = Group; | ||
3530 | } | ||
3531 | Groupupdate.GroupData = Groups; | ||
3532 | Groupupdate.AgentData = new AgentGroupDataUpdatePacket.AgentDataBlock(); | ||
3533 | Groupupdate.AgentData.AgentID = avatarID; | ||
3534 | OutPacket(Groupupdate, ThrottleOutPacketType.Task); | ||
3535 | } | ||
3536 | } | ||
3537 | |||
3413 | public void SendJoinGroupReply(UUID groupID, bool success) | 3538 | public void SendJoinGroupReply(UUID groupID, bool success) |
3414 | { | 3539 | { |
3415 | JoinGroupReplyPacket p = (JoinGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.JoinGroupReply); | 3540 | JoinGroupReplyPacket p = (JoinGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.JoinGroupReply); |
@@ -3649,6 +3774,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3649 | OutPacket(useCachedMuteList, ThrottleOutPacketType.Task); | 3774 | OutPacket(useCachedMuteList, ThrottleOutPacketType.Task); |
3650 | } | 3775 | } |
3651 | 3776 | ||
3777 | public void SendEmpytMuteList() | ||
3778 | { | ||
3779 | GenericMessagePacket gmp = new GenericMessagePacket(); | ||
3780 | |||
3781 | gmp.AgentData.AgentID = AgentId; | ||
3782 | gmp.AgentData.SessionID = m_sessionId; | ||
3783 | gmp.AgentData.TransactionID = UUID.Zero; | ||
3784 | |||
3785 | gmp.MethodData.Method = Util.StringToBytes256("emptymutelist"); | ||
3786 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[1]; | ||
3787 | gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock(); | ||
3788 | gmp.ParamList[0].Parameter = new byte[0]; | ||
3789 | |||
3790 | OutPacket(gmp, ThrottleOutPacketType.Task); | ||
3791 | } | ||
3792 | |||
3652 | public void SendMuteListUpdate(string filename) | 3793 | public void SendMuteListUpdate(string filename) |
3653 | { | 3794 | { |
3654 | MuteListUpdatePacket muteListUpdate = (MuteListUpdatePacket)PacketPool.Instance.GetPacket(PacketType.MuteListUpdate); | 3795 | MuteListUpdatePacket muteListUpdate = (MuteListUpdatePacket)PacketPool.Instance.GetPacket(PacketType.MuteListUpdate); |
@@ -3706,24 +3847,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3706 | aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; | 3847 | aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; |
3707 | AgentWearablesUpdatePacket.WearableDataBlock awb; | 3848 | AgentWearablesUpdatePacket.WearableDataBlock awb; |
3708 | int idx = 0; | 3849 | int idx = 0; |
3709 | for (int i = 0; i < wearables.Length; i++) | ||
3710 | { | ||
3711 | for (int j = 0; j < wearables[i].Count; j++) | ||
3712 | { | ||
3713 | awb = new AgentWearablesUpdatePacket.WearableDataBlock(); | ||
3714 | awb.WearableType = (byte)i; | ||
3715 | awb.AssetID = wearables[i][j].AssetID; | ||
3716 | awb.ItemID = wearables[i][j].ItemID; | ||
3717 | aw.WearableData[idx] = awb; | ||
3718 | idx++; | ||
3719 | 3850 | ||
3720 | // m_log.DebugFormat( | 3851 | for (int i = 0; i < wearables.Length; i++) |
3721 | // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", | 3852 | { |
3722 | // awb.ItemID, awb.AssetID, i, Name); | 3853 | for (int j = 0; j < wearables[i].Count; j++) |
3723 | } | 3854 | { |
3724 | } | 3855 | awb = new AgentWearablesUpdatePacket.WearableDataBlock(); |
3856 | awb.WearableType = (byte) i; | ||
3857 | awb.AssetID = wearables[i][j].AssetID; | ||
3858 | awb.ItemID = wearables[i][j].ItemID; | ||
3859 | aw.WearableData[idx] = awb; | ||
3860 | idx++; | ||
3861 | |||
3862 | // m_log.DebugFormat( | ||
3863 | // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", | ||
3864 | // awb.ItemID, awb.AssetID, i, Name); | ||
3865 | } | ||
3866 | } | ||
3725 | 3867 | ||
3726 | OutPacket(aw, ThrottleOutPacketType.Task); | 3868 | OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); |
3727 | } | 3869 | } |
3728 | 3870 | ||
3729 | public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) | 3871 | public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) |
@@ -3749,8 +3891,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3749 | avp.Sender.ID = agentID; | 3891 | avp.Sender.ID = agentID; |
3750 | avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; | 3892 | avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; |
3751 | avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0]; | 3893 | avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0]; |
3894 | |||
3895 | // this need be use in future ? | ||
3896 | // avp.AppearanceData[0].AppearanceVersion = 0; | ||
3897 | // avp.AppearanceData[0].CofVersion = 0; | ||
3898 | |||
3752 | //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); | 3899 | //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); |
3753 | OutPacket(avp, ThrottleOutPacketType.Task); | 3900 | OutPacket(avp, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); |
3754 | } | 3901 | } |
3755 | 3902 | ||
3756 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) | 3903 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) |
@@ -3778,7 +3925,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3778 | ani.AnimationSourceList[i].ObjectID = objectIDs[i]; | 3925 | ani.AnimationSourceList[i].ObjectID = objectIDs[i]; |
3779 | } | 3926 | } |
3780 | ani.Header.Reliable = false; | 3927 | ani.Header.Reliable = false; |
3781 | OutPacket(ani, ThrottleOutPacketType.Task); | 3928 | OutPacket(ani, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); |
3782 | } | 3929 | } |
3783 | 3930 | ||
3784 | #endregion | 3931 | #endregion |
@@ -3788,26 +3935,70 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3788 | /// <summary> | 3935 | /// <summary> |
3789 | /// Send an ObjectUpdate packet with information about an avatar | 3936 | /// Send an ObjectUpdate packet with information about an avatar |
3790 | /// </summary> | 3937 | /// </summary> |
3791 | public void SendAvatarDataImmediate(ISceneEntity avatar) | 3938 | public void SendEntityFullUpdateImmediate(ISceneEntity ent) |
3792 | { | 3939 | { |
3793 | // m_log.DebugFormat( | 3940 | // m_log.DebugFormat( |
3794 | // "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}", | 3941 | // "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}", |
3795 | // avatar.Name, avatar.UUID, Name, AgentId); | 3942 | // avatar.Name, avatar.UUID, Name, AgentId); |
3796 | 3943 | ||
3797 | ScenePresence presence = avatar as ScenePresence; | 3944 | if (ent == null) |
3798 | if (presence == null) | ||
3799 | return; | 3945 | return; |
3800 | 3946 | ||
3801 | ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | 3947 | ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); |
3802 | objupdate.Header.Zerocoded = true; | 3948 | objupdate.Header.Zerocoded = true; |
3803 | 3949 | ||
3804 | objupdate.RegionData.RegionHandle = presence.RegionHandle; | 3950 | objupdate.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); |
3805 | objupdate.RegionData.TimeDilation = ushort.MaxValue; | ||
3806 | |||
3807 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | 3951 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; |
3808 | objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence); | ||
3809 | 3952 | ||
3810 | OutPacket(objupdate, ThrottleOutPacketType.Task); | 3953 | if(ent is ScenePresence) |
3954 | { | ||
3955 | ScenePresence presence = ent as ScenePresence; | ||
3956 | objupdate.RegionData.RegionHandle = presence.RegionHandle; | ||
3957 | objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence); | ||
3958 | } | ||
3959 | else if(ent is SceneObjectPart) | ||
3960 | { | ||
3961 | SceneObjectPart part = ent as SceneObjectPart; | ||
3962 | objupdate.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
3963 | objupdate.ObjectData[0] = CreatePrimUpdateBlock(part, (ScenePresence)SceneAgent); | ||
3964 | } | ||
3965 | |||
3966 | OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); | ||
3967 | |||
3968 | // We need to record the avatar local id since the root prim of an attachment points to this. | ||
3969 | // m_attachmentsSent.Add(avatar.LocalId); | ||
3970 | } | ||
3971 | |||
3972 | public void SendEntityTerseUpdateImmediate(ISceneEntity ent) | ||
3973 | { | ||
3974 | // m_log.DebugFormat( | ||
3975 | // "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}", | ||
3976 | // avatar.Name, avatar.UUID, Name, AgentId); | ||
3977 | |||
3978 | if (ent == null) | ||
3979 | return; | ||
3980 | |||
3981 | ImprovedTerseObjectUpdatePacket objupdate = | ||
3982 | (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); | ||
3983 | objupdate.Header.Zerocoded = true; | ||
3984 | |||
3985 | objupdate.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); | ||
3986 | objupdate.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; | ||
3987 | |||
3988 | if(ent is ScenePresence) | ||
3989 | { | ||
3990 | ScenePresence presence = ent as ScenePresence; | ||
3991 | objupdate.RegionData.RegionHandle = presence.RegionHandle; | ||
3992 | objupdate.ObjectData[0] = CreateImprovedTerseBlock(ent, false); | ||
3993 | } | ||
3994 | else if(ent is SceneObjectPart) | ||
3995 | { | ||
3996 | SceneObjectPart part = ent as SceneObjectPart; | ||
3997 | objupdate.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
3998 | objupdate.ObjectData[0] = CreateImprovedTerseBlock(ent, false); | ||
3999 | } | ||
4000 | |||
4001 | OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); | ||
3811 | 4002 | ||
3812 | // We need to record the avatar local id since the root prim of an attachment points to this. | 4003 | // We need to record the avatar local id since the root prim of an attachment points to this. |
3813 | // m_attachmentsSent.Add(avatar.LocalId); | 4004 | // m_attachmentsSent.Add(avatar.LocalId); |
@@ -3859,13 +4050,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3859 | 4050 | ||
3860 | #region Primitive Packet/Data Sending Methods | 4051 | #region Primitive Packet/Data Sending Methods |
3861 | 4052 | ||
3862 | |||
3863 | /// <summary> | 4053 | /// <summary> |
3864 | /// Generate one of the object update packets based on PrimUpdateFlags | 4054 | /// Generate one of the object update packets based on PrimUpdateFlags |
3865 | /// and broadcast the packet to clients | 4055 | /// and broadcast the packet to clients |
3866 | /// </summary> | 4056 | /// </summary> |
3867 | public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) | 4057 | public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) |
3868 | { | 4058 | { |
4059 | /* | ||
3869 | if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) | 4060 | if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) |
3870 | { | 4061 | { |
3871 | ImprovedTerseObjectUpdatePacket packet | 4062 | ImprovedTerseObjectUpdatePacket packet |
@@ -3876,21 +4067,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3876 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; | 4067 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; |
3877 | packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false); | 4068 | packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false); |
3878 | OutPacket(packet, ThrottleOutPacketType.Unknown, true); | 4069 | OutPacket(packet, ThrottleOutPacketType.Unknown, true); |
4070 | return; | ||
3879 | } | 4071 | } |
3880 | else | 4072 | */ |
4073 | if (entity is SceneObjectPart) | ||
3881 | { | 4074 | { |
3882 | //double priority = m_prioritizer.GetUpdatePriority(this, entity); | 4075 | SceneObjectPart p = (SceneObjectPart)entity; |
3883 | uint priority = m_prioritizer.GetUpdatePriority(this, entity); | 4076 | SceneObjectGroup g = p.ParentGroup; |
3884 | 4077 | if (g.HasPrivateAttachmentPoint && g.OwnerID != AgentId) | |
3885 | lock (m_entityUpdates.SyncRoot) | 4078 | return; // Don't send updates for other people's HUDs |
3886 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); | 4079 | |
4080 | if((updateFlags ^ PrimUpdateFlags.SendInTransit) == 0) | ||
4081 | { | ||
4082 | List<uint> partIDs = (new List<uint> {p.LocalId}); | ||
4083 | lock (m_entityProps.SyncRoot) | ||
4084 | m_entityProps.Remove(partIDs); | ||
4085 | lock (m_entityUpdates.SyncRoot) | ||
4086 | m_entityUpdates.Remove(partIDs); | ||
4087 | return; | ||
4088 | } | ||
3887 | } | 4089 | } |
4090 | |||
4091 | //double priority = m_prioritizer.GetUpdatePriority(this, entity); | ||
4092 | uint priority = m_prioritizer.GetUpdatePriority(this, entity); | ||
4093 | |||
4094 | lock (m_entityUpdates.SyncRoot) | ||
4095 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags)); | ||
3888 | } | 4096 | } |
3889 | 4097 | ||
3890 | /// <summary> | 4098 | /// <summary> |
3891 | /// Requeue an EntityUpdate when it was not acknowledged by the client. | 4099 | /// Requeue an EntityUpdate when it was not acknowledged by the client. |
3892 | /// We will update the priority and put it in the correct queue, merging update flags | 4100 | /// We will update the priority and put it in the correct queue, merging update flags |
3893 | /// with any other updates that may be queued for the same entity. | 4101 | /// with any other updates that may be queued for the same entity. |
3894 | /// The original update time is used for the merged update. | 4102 | /// The original update time is used for the merged update. |
3895 | /// </summary> | 4103 | /// </summary> |
3896 | private void ResendPrimUpdate(EntityUpdate update) | 4104 | private void ResendPrimUpdate(EntityUpdate update) |
@@ -3904,9 +4112,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3904 | } | 4112 | } |
3905 | 4113 | ||
3906 | /// <summary> | 4114 | /// <summary> |
3907 | /// Requeue a list of EntityUpdates when they were not acknowledged by the client. | 4115 | /// Requeue a list of EntityUpdates when they were not acknowledged by the client. |
3908 | /// We will update the priority and put it in the correct queue, merging update flags | 4116 | /// We will update the priority and put it in the correct queue, merging update flags |
3909 | /// with any other updates that may be queued for the same entity. | 4117 | /// with any other updates that may be queued for the same entity. |
3910 | /// The original update time is used for the merged update. | 4118 | /// The original update time is used for the merged update. |
3911 | /// </summary> | 4119 | /// </summary> |
3912 | private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket) | 4120 | private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket) |
@@ -3919,7 +4127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3919 | m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); | 4127 | m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); |
3920 | 4128 | ||
3921 | // Count this as a resent packet since we are going to requeue all of the updates contained in it | 4129 | // Count this as a resent packet since we are going to requeue all of the updates contained in it |
3922 | Interlocked.Increment(ref m_udpClient.PacketsResent); | 4130 | Interlocked.Increment(ref m_udpClient.PacketsResent); |
3923 | 4131 | ||
3924 | // We're not going to worry about interlock yet since its not currently critical that this total count | 4132 | // We're not going to worry about interlock yet since its not currently critical that this total count |
3925 | // is 100% correct | 4133 | // is 100% correct |
@@ -3929,335 +4137,515 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3929 | ResendPrimUpdate(update); | 4137 | ResendPrimUpdate(update); |
3930 | } | 4138 | } |
3931 | 4139 | ||
3932 | // OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | 4140 | private List<ObjectUpdatePacket.ObjectDataBlock> objectUpdateBlocks = new List<ObjectUpdatePacket.ObjectDataBlock>(); |
3933 | // OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>(); | 4141 | private List<ObjectUpdateCompressedPacket.ObjectDataBlock> compressedUpdateBlocks = new List<ObjectUpdateCompressedPacket.ObjectDataBlock>(); |
3934 | // OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | 4142 | private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> terseUpdateBlocks = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); |
3935 | // OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | 4143 | private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> terseAgentUpdateBlocks = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); |
3936 | // | ||
3937 | // OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3938 | // OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3939 | // OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3940 | // OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3941 | |||
3942 | 4144 | ||
3943 | private void ProcessEntityUpdates(int maxUpdates) | 4145 | private void ProcessEntityUpdates(int maxUpdatesBytes) |
3944 | { | 4146 | { |
3945 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | ||
3946 | OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>(); | ||
3947 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | ||
3948 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | ||
3949 | |||
3950 | OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | 4147 | OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); |
3951 | OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | 4148 | OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); |
3952 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | 4149 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); |
3953 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | 4150 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); |
3954 | 4151 | ||
3955 | // objectUpdateBlocks.Value.Clear(); | ||
3956 | // compressedUpdateBlocks.Value.Clear(); | ||
3957 | // terseUpdateBlocks.Value.Clear(); | ||
3958 | // terseAgentUpdateBlocks.Value.Clear(); | ||
3959 | // objectUpdates.Value.Clear(); | ||
3960 | // compressedUpdates.Value.Clear(); | ||
3961 | // terseUpdates.Value.Clear(); | ||
3962 | // terseAgentUpdates.Value.Clear(); | ||
3963 | |||
3964 | // Check to see if this is a flush | 4152 | // Check to see if this is a flush |
3965 | if (maxUpdates <= 0) | 4153 | if (maxUpdatesBytes <= 0) |
3966 | { | 4154 | { |
3967 | maxUpdates = Int32.MaxValue; | 4155 | maxUpdatesBytes = Int32.MaxValue; |
3968 | } | 4156 | } |
3969 | 4157 | ||
3970 | int updatesThisCall = 0; | 4158 | EntityUpdate update; |
4159 | Int32 timeinqueue; // this is just debugging code & can be dropped later | ||
4160 | |||
4161 | bool doCulling = m_scene.ObjectsCullingByDistance; | ||
4162 | float cullingrange = 64.0f; | ||
4163 | HashSet<SceneObjectGroup> GroupsNeedFullUpdate = new HashSet<SceneObjectGroup>(); | ||
4164 | // Vector3 mycamera = Vector3.Zero; | ||
4165 | Vector3 mypos = Vector3.Zero; | ||
4166 | ScenePresence mysp = (ScenePresence)SceneAgent; | ||
4167 | |||
4168 | bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance; | ||
4169 | // we should have a presence | ||
4170 | if(mysp == null) | ||
4171 | return; | ||
3971 | 4172 | ||
3972 | // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race | 4173 | if(doCulling) |
3973 | // condition where a kill can be processed before an out-of-date update for the same object. | ||
3974 | lock (m_killRecord) | ||
3975 | { | 4174 | { |
3976 | float avgTimeDilation = 1.0f; | 4175 | cullingrange = mysp.DrawDistance + m_scene.ReprioritizationDistance + 16f; |
3977 | IEntityUpdate iupdate; | 4176 | // mycamera = mysp.CameraPosition; |
3978 | Int32 timeinqueue; // this is just debugging code & can be dropped later | 4177 | mypos = mysp.AbsolutePosition; |
4178 | } | ||
3979 | 4179 | ||
3980 | while (updatesThisCall < maxUpdates) | 4180 | while (maxUpdatesBytes > 0) |
4181 | { | ||
4182 | lock (m_entityUpdates.SyncRoot) | ||
3981 | { | 4183 | { |
3982 | lock (m_entityUpdates.SyncRoot) | 4184 | if(orderedDequeue) |
3983 | if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue)) | 4185 | { |
4186 | if (!m_entityUpdates.TryOrderedDequeue(out update, out timeinqueue)) | ||
3984 | break; | 4187 | break; |
4188 | } | ||
4189 | else | ||
4190 | { | ||
4191 | if (!m_entityUpdates.TryDequeue(out update, out timeinqueue)) | ||
4192 | break; | ||
4193 | } | ||
4194 | } | ||
3985 | 4195 | ||
3986 | EntityUpdate update = (EntityUpdate)iupdate; | 4196 | PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; |
3987 | |||
3988 | avgTimeDilation += update.TimeDilation; | ||
3989 | avgTimeDilation *= 0.5f; | ||
3990 | 4197 | ||
3991 | if (update.Entity is SceneObjectPart) | 4198 | if(updateFlags.HasFlag(PrimUpdateFlags.Kill)) |
4199 | { | ||
4200 | m_killRecord.Add(update.Entity.LocalId); | ||
4201 | maxUpdatesBytes -= 30; | ||
4202 | continue; | ||
4203 | } | ||
4204 | |||
4205 | if (update.Entity is SceneObjectPart) | ||
4206 | { | ||
4207 | SceneObjectPart part = (SceneObjectPart)update.Entity; | ||
4208 | SceneObjectGroup grp = part.ParentGroup; | ||
4209 | if (grp.inTransit && !update.Flags.HasFlag(PrimUpdateFlags.SendInTransit)) | ||
4210 | continue; | ||
4211 | /* debug | ||
4212 | if (update.Flags.HasFlag(PrimUpdateFlags.SendInTransit)) | ||
4213 | { | ||
4214 | |||
4215 | |||
4216 | } | ||
4217 | */ | ||
4218 | if (grp.IsDeleted) | ||
3992 | { | 4219 | { |
3993 | SceneObjectPart part = (SceneObjectPart)update.Entity; | 4220 | // Don't send updates for objects that have been marked deleted. |
3994 | 4221 | // Instead send another kill object, because the first one may have gotten | |
3995 | // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client | 4222 | // into a race condition |
3996 | // will never receive an update after a prim kill. Even then, keeping the kill record may be a good | 4223 | if (part == grp.RootPart && !m_killRecord.Contains(grp.LocalId)) |
3997 | // safety measure. | ||
3998 | // | ||
3999 | // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update | ||
4000 | // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs | ||
4001 | // updates and kills on different threads with different scheduling strategies, hence this protection. | ||
4002 | // | ||
4003 | // This doesn't appear to apply to child prims - a client will happily ignore these updates | ||
4004 | // after the root prim has been deleted. | ||
4005 | if (m_killRecord.Contains(part.LocalId)) | ||
4006 | { | 4224 | { |
4007 | // m_log.WarnFormat( | 4225 | m_killRecord.Add(grp.LocalId); |
4008 | // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", | 4226 | maxUpdatesBytes -= 30; |
4009 | // part.LocalId, Name); | 4227 | } |
4228 | continue; | ||
4229 | } | ||
4230 | |||
4231 | if (grp.IsAttachment) | ||
4232 | { // Someone else's HUD, why are we getting these? | ||
4233 | if (grp.OwnerID != AgentId && grp.HasPrivateAttachmentPoint) | ||
4234 | continue; | ||
4235 | ScenePresence sp; | ||
4236 | // Owner is not in the sim, don't update it to | ||
4237 | // anyone | ||
4238 | if (!m_scene.TryGetScenePresence(part.OwnerID, out sp)) | ||
4010 | continue; | 4239 | continue; |
4011 | } | 4240 | |
4012 | 4241 | List<SceneObjectGroup> atts = sp.GetAttachments(); | |
4013 | if (part.ParentGroup.IsAttachment && m_disableFacelights) | 4242 | bool found = false; |
4243 | foreach (SceneObjectGroup att in atts) | ||
4014 | { | 4244 | { |
4015 | if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && | 4245 | if (att == grp) |
4016 | part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand) | ||
4017 | { | 4246 | { |
4018 | part.Shape.LightEntry = false; | 4247 | found = true; |
4248 | break; | ||
4019 | } | 4249 | } |
4020 | } | 4250 | } |
4021 | 4251 | ||
4022 | if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) | 4252 | // It's an attachment of a valid avatar, but |
4023 | { | 4253 | // doesn't seem to be attached, skip |
4024 | // Ensure that mesh has at least 8 valid faces | 4254 | if (!found) |
4025 | part.Shape.ProfileBegin = 12500; | 4255 | continue; |
4026 | part.Shape.ProfileEnd = 0; | 4256 | |
4027 | part.Shape.ProfileHollow = 27500; | 4257 | // On vehicle crossing, the attachments are received |
4028 | } | 4258 | // while the avatar is still a child. Don't send |
4029 | } | 4259 | // updates here because the LocalId has not yet |
4030 | 4260 | // been updated and the viewer will derender the | |
4031 | #region UpdateFlags to packet type conversion | 4261 | // attachments until the avatar becomes root. |
4032 | 4262 | if (sp.IsChildAgent) | |
4033 | PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; | 4263 | continue; |
4034 | 4264 | ||
4035 | bool canUseCompressed = true; | ||
4036 | bool canUseImproved = true; | ||
4037 | |||
4038 | // Compressed object updates only make sense for LL primitives | ||
4039 | if (!(update.Entity is SceneObjectPart)) | ||
4040 | { | ||
4041 | canUseCompressed = false; | ||
4042 | } | ||
4043 | |||
4044 | if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) | ||
4045 | { | ||
4046 | canUseCompressed = false; | ||
4047 | canUseImproved = false; | ||
4048 | } | 4265 | } |
4049 | else | 4266 | |
4267 | if (grp.IsAttachment && m_disableFacelights) | ||
4050 | { | 4268 | { |
4051 | if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || | 4269 | if (grp.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && |
4052 | updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || | 4270 | grp.RootPart.Shape.State != (byte)AttachmentPoint.RightHand) |
4053 | updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) || | ||
4054 | updateFlags.HasFlag(PrimUpdateFlags.Joint)) | ||
4055 | { | ||
4056 | canUseCompressed = false; | ||
4057 | } | ||
4058 | |||
4059 | if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) || | ||
4060 | updateFlags.HasFlag(PrimUpdateFlags.ParentID) || | ||
4061 | updateFlags.HasFlag(PrimUpdateFlags.Scale) || | ||
4062 | updateFlags.HasFlag(PrimUpdateFlags.PrimData) || | ||
4063 | updateFlags.HasFlag(PrimUpdateFlags.Text) || | ||
4064 | updateFlags.HasFlag(PrimUpdateFlags.NameValue) || | ||
4065 | updateFlags.HasFlag(PrimUpdateFlags.ExtraData) || | ||
4066 | updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) || | ||
4067 | updateFlags.HasFlag(PrimUpdateFlags.Sound) || | ||
4068 | updateFlags.HasFlag(PrimUpdateFlags.Particles) || | ||
4069 | updateFlags.HasFlag(PrimUpdateFlags.Material) || | ||
4070 | updateFlags.HasFlag(PrimUpdateFlags.ClickAction) || | ||
4071 | updateFlags.HasFlag(PrimUpdateFlags.MediaURL) || | ||
4072 | updateFlags.HasFlag(PrimUpdateFlags.Joint)) | ||
4073 | { | 4271 | { |
4074 | canUseImproved = false; | 4272 | part.Shape.LightEntry = false; |
4075 | } | 4273 | } |
4076 | } | 4274 | } |
4077 | 4275 | ||
4078 | #endregion UpdateFlags to packet type conversion | 4276 | if(doCulling && !grp.IsAttachment) |
4079 | |||
4080 | #region Block Construction | ||
4081 | |||
4082 | // TODO: Remove this once we can build compressed updates | ||
4083 | canUseCompressed = false; | ||
4084 | |||
4085 | if (!canUseImproved && !canUseCompressed) | ||
4086 | { | 4277 | { |
4087 | ObjectUpdatePacket.ObjectDataBlock updateBlock; | 4278 | if(GroupsNeedFullUpdate.Contains(grp)) |
4279 | continue; | ||
4088 | 4280 | ||
4089 | if (update.Entity is ScenePresence) | 4281 | bool inview = false; |
4090 | { | 4282 | lock(GroupsInView) |
4091 | updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity); | 4283 | inview = GroupsInView.Contains(grp); |
4092 | } | 4284 | |
4093 | else | 4285 | if(!inview) |
4094 | { | 4286 | { |
4095 | SceneObjectPart part = (SceneObjectPart)update.Entity; | 4287 | float bradius = grp.GetBoundsRadius(); |
4096 | updateBlock = CreatePrimUpdateBlock(part, AgentId); | 4288 | Vector3 partpos = grp.AbsolutePosition + grp.getBoundsCenter(); |
4097 | 4289 | // float dcam = (partpos - mycamera).LengthSquared(); | |
4098 | // If the part has become a private hud since the update was scheduled then we do not | 4290 | float dpos = (partpos - mypos).LengthSquared(); |
4099 | // want to send it to other avatars. | 4291 | // if(dcam < dpos) |
4100 | if (part.ParentGroup.IsAttachment | 4292 | // dpos = dcam; |
4101 | && part.ParentGroup.HasPrivateAttachmentPoint | 4293 | dpos = (float)Math.Sqrt(dpos) - bradius; |
4102 | && part.ParentGroup.AttachedAvatar != AgentId) | 4294 | if(dpos > cullingrange) |
4103 | continue; | 4295 | continue; |
4104 | 4296 | ||
4105 | // If the part has since been deleted, then drop the update. In the case of attachments, | 4297 | GroupsNeedFullUpdate.Add(grp); |
4106 | // this is to avoid spurious updates to other viewers since post-processing of attachments | 4298 | continue; |
4107 | // has to change the IsAttachment flag for various reasons (which will end up in a pass | ||
4108 | // of the test above). | ||
4109 | // | ||
4110 | // Actual deletions (kills) happen in another method. | ||
4111 | if (part.ParentGroup.IsDeleted) | ||
4112 | continue; | ||
4113 | } | 4299 | } |
4300 | } | ||
4301 | } | ||
4302 | else if (update.Entity is ScenePresence) | ||
4303 | { | ||
4304 | ScenePresence presence = (ScenePresence)update.Entity; | ||
4305 | if (presence.IsDeleted) | ||
4306 | continue; | ||
4307 | // If ParentUUID is not UUID.Zero and ParentID is 0, this | ||
4308 | // avatar is in the process of crossing regions while | ||
4309 | // sat on an object. In this state, we don't want any | ||
4310 | // updates because they will visually orbit the avatar. | ||
4311 | // Update will be forced once crossing is completed anyway. | ||
4312 | if (presence.ParentUUID != UUID.Zero && presence.ParentID == 0) | ||
4313 | continue; | ||
4314 | } | ||
4315 | |||
4316 | #region UpdateFlags to packet type conversion | ||
4317 | |||
4318 | bool canUseCompressed = true; | ||
4319 | bool canUseImproved = true; | ||
4320 | |||
4321 | |||
4322 | // Compressed object updates only make sense for LL primitives | ||
4323 | if (!(update.Entity is SceneObjectPart)) | ||
4324 | { | ||
4325 | canUseCompressed = false; | ||
4326 | } | ||
4114 | 4327 | ||
4115 | objectUpdateBlocks.Value.Add(updateBlock); | 4328 | if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) |
4116 | objectUpdates.Value.Add(update); | 4329 | { |
4330 | canUseCompressed = false; | ||
4331 | canUseImproved = false; | ||
4332 | } | ||
4333 | else | ||
4334 | { | ||
4335 | if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || | ||
4336 | updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || | ||
4337 | updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) || | ||
4338 | updateFlags.HasFlag(PrimUpdateFlags.Joint)) | ||
4339 | { | ||
4340 | canUseCompressed = false; | ||
4117 | } | 4341 | } |
4118 | else if (!canUseImproved) | 4342 | |
4343 | if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) || | ||
4344 | updateFlags.HasFlag(PrimUpdateFlags.ParentID) || | ||
4345 | updateFlags.HasFlag(PrimUpdateFlags.Scale) || | ||
4346 | updateFlags.HasFlag(PrimUpdateFlags.PrimData) || | ||
4347 | updateFlags.HasFlag(PrimUpdateFlags.Text) || | ||
4348 | updateFlags.HasFlag(PrimUpdateFlags.NameValue) || | ||
4349 | updateFlags.HasFlag(PrimUpdateFlags.ExtraData) || | ||
4350 | updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) || | ||
4351 | updateFlags.HasFlag(PrimUpdateFlags.Sound) || | ||
4352 | updateFlags.HasFlag(PrimUpdateFlags.Particles) || | ||
4353 | updateFlags.HasFlag(PrimUpdateFlags.Material) || | ||
4354 | updateFlags.HasFlag(PrimUpdateFlags.ClickAction) || | ||
4355 | updateFlags.HasFlag(PrimUpdateFlags.MediaURL) || | ||
4356 | updateFlags.HasFlag(PrimUpdateFlags.Joint)) | ||
4119 | { | 4357 | { |
4120 | SceneObjectPart part = (SceneObjectPart)update.Entity; | 4358 | canUseImproved = false; |
4121 | ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock | 4359 | } |
4122 | = CreateCompressedUpdateBlock(part, updateFlags); | 4360 | } |
4123 | 4361 | ||
4124 | // If the part has since been deleted, then drop the update. In the case of attachments, | 4362 | #endregion UpdateFlags to packet type conversion |
4125 | // this is to avoid spurious updates to other viewers since post-processing of attachments | ||
4126 | // has to change the IsAttachment flag for various reasons (which will end up in a pass | ||
4127 | // of the test above). | ||
4128 | // | ||
4129 | // Actual deletions (kills) happen in another method. | ||
4130 | if (part.ParentGroup.IsDeleted) | ||
4131 | continue; | ||
4132 | 4363 | ||
4133 | compressedUpdateBlocks.Value.Add(compressedBlock); | 4364 | #region Block Construction |
4134 | compressedUpdates.Value.Add(update); | 4365 | |
4366 | // TODO: Remove this once we can build compressed updates | ||
4367 | canUseCompressed = false; | ||
4368 | |||
4369 | if (!canUseImproved && !canUseCompressed) | ||
4370 | { | ||
4371 | ObjectUpdatePacket.ObjectDataBlock ablock; | ||
4372 | if (update.Entity is ScenePresence) | ||
4373 | ablock = CreateAvatarUpdateBlock((ScenePresence)update.Entity); | ||
4374 | else | ||
4375 | ablock = CreatePrimUpdateBlock((SceneObjectPart)update.Entity, mysp); | ||
4376 | objectUpdateBlocks.Add(ablock); | ||
4377 | objectUpdates.Value.Add(update); | ||
4378 | maxUpdatesBytes -= ablock.Length; | ||
4379 | |||
4380 | } | ||
4381 | else if (!canUseImproved) | ||
4382 | { | ||
4383 | ObjectUpdateCompressedPacket.ObjectDataBlock ablock = | ||
4384 | CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags); | ||
4385 | compressedUpdateBlocks.Add(ablock); | ||
4386 | compressedUpdates.Value.Add(update); | ||
4387 | maxUpdatesBytes -= ablock.Length; | ||
4388 | } | ||
4389 | else | ||
4390 | { | ||
4391 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock ablock; | ||
4392 | if (update.Entity is ScenePresence) | ||
4393 | { | ||
4394 | // ALL presence updates go into a special list | ||
4395 | ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)); | ||
4396 | terseAgentUpdateBlocks.Add(ablock); | ||
4397 | terseAgentUpdates.Value.Add(update); | ||
4135 | } | 4398 | } |
4136 | else | 4399 | else |
4137 | { | 4400 | { |
4138 | if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) | 4401 | // Everything else goes here |
4139 | { | 4402 | ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)); |
4140 | // Self updates go into a special list | 4403 | terseUpdateBlocks.Add(ablock); |
4141 | terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); | 4404 | terseUpdates.Value.Add(update); |
4142 | terseAgentUpdates.Value.Add(update); | 4405 | } |
4143 | } | 4406 | maxUpdatesBytes -= ablock.Length; |
4144 | else | 4407 | } |
4145 | { | ||
4146 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock | ||
4147 | = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)); | ||
4148 | 4408 | ||
4149 | // Everything else goes here | 4409 | #endregion Block Construction |
4150 | if (update.Entity is SceneObjectPart) | 4410 | } |
4151 | { | ||
4152 | SceneObjectPart part = (SceneObjectPart)update.Entity; | ||
4153 | |||
4154 | // If the part has become a private hud since the update was scheduled then we do not | ||
4155 | // want to send it to other avatars. | ||
4156 | if (part.ParentGroup.IsAttachment | ||
4157 | && part.ParentGroup.HasPrivateAttachmentPoint | ||
4158 | && part.ParentGroup.AttachedAvatar != AgentId) | ||
4159 | continue; | ||
4160 | |||
4161 | // If the part has since been deleted, then drop the update. In the case of attachments, | ||
4162 | // this is to avoid spurious updates to other viewers since post-processing of attachments | ||
4163 | // has to change the IsAttachment flag for various reasons (which will end up in a pass | ||
4164 | // of the test above). | ||
4165 | // | ||
4166 | // Actual deletions (kills) happen in another method. | ||
4167 | if (part.ParentGroup.IsDeleted) | ||
4168 | continue; | ||
4169 | } | ||
4170 | 4411 | ||
4171 | terseUpdateBlocks.Value.Add(terseUpdateBlock); | 4412 | #region Packet Sending |
4172 | terseUpdates.Value.Add(update); | ||
4173 | } | ||
4174 | } | ||
4175 | 4413 | ||
4176 | ++updatesThisCall; | 4414 | ushort timeDilation; |
4177 | |||
4178 | #endregion Block Construction | ||
4179 | } | ||
4180 | |||
4181 | #region Packet Sending | ||
4182 | ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); | ||
4183 | 4415 | ||
4184 | if (terseAgentUpdateBlocks.IsValueCreated) | 4416 | if(!IsActive) |
4185 | { | 4417 | return; |
4186 | List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; | 4418 | |
4419 | timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); | ||
4187 | 4420 | ||
4188 | ImprovedTerseObjectUpdatePacket packet | 4421 | if (terseAgentUpdateBlocks.Count > 0) |
4189 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); | 4422 | { |
4423 | ImprovedTerseObjectUpdatePacket packet | ||
4424 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); | ||
4425 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
4426 | packet.RegionData.TimeDilation = timeDilation; | ||
4427 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseAgentUpdateBlocks.Count]; | ||
4190 | 4428 | ||
4191 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | 4429 | for (int i = 0; i < terseAgentUpdateBlocks.Count; i++) |
4192 | packet.RegionData.TimeDilation = timeDilation; | 4430 | packet.ObjectData[i] = terseAgentUpdateBlocks[i]; |
4193 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
4194 | 4431 | ||
4195 | for (int i = 0; i < blocks.Count; i++) | 4432 | terseAgentUpdateBlocks.Clear(); |
4196 | packet.ObjectData[i] = blocks[i]; | 4433 | |
4197 | // If any of the packets created from this call go unacknowledged, all of the updates will be resent | 4434 | OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); |
4198 | OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); | 4435 | } |
4199 | } | 4436 | |
4437 | if (objectUpdateBlocks.Count > 0) | ||
4438 | { | ||
4439 | ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | ||
4440 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
4441 | packet.RegionData.TimeDilation = timeDilation; | ||
4442 | packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[objectUpdateBlocks.Count]; | ||
4443 | |||
4444 | for (int i = 0; i < objectUpdateBlocks.Count; i++) | ||
4445 | packet.ObjectData[i] = objectUpdateBlocks[i]; | ||
4446 | |||
4447 | objectUpdateBlocks.Clear(); | ||
4448 | |||
4449 | OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); }); | ||
4450 | } | ||
4451 | |||
4452 | if (compressedUpdateBlocks.Count > 0) | ||
4453 | { | ||
4454 | ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); | ||
4455 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
4456 | packet.RegionData.TimeDilation = timeDilation; | ||
4457 | packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[compressedUpdateBlocks.Count]; | ||
4458 | |||
4459 | for (int i = 0; i < compressedUpdateBlocks.Count; i++) | ||
4460 | packet.ObjectData[i] = compressedUpdateBlocks[i]; | ||
4461 | |||
4462 | compressedUpdateBlocks.Clear(); | ||
4200 | 4463 | ||
4201 | if (objectUpdateBlocks.IsValueCreated) | 4464 | OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); }); |
4465 | } | ||
4466 | |||
4467 | if (terseUpdateBlocks.Count > 0) | ||
4468 | { | ||
4469 | ImprovedTerseObjectUpdatePacket packet | ||
4470 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( | ||
4471 | PacketType.ImprovedTerseObjectUpdate); | ||
4472 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
4473 | packet.RegionData.TimeDilation = timeDilation; | ||
4474 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseUpdateBlocks.Count]; | ||
4475 | |||
4476 | for (int i = 0; i < terseUpdateBlocks.Count; i++) | ||
4477 | packet.ObjectData[i] = terseUpdateBlocks[i]; | ||
4478 | |||
4479 | terseUpdateBlocks.Clear(); | ||
4480 | |||
4481 | OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); | ||
4482 | } | ||
4483 | |||
4484 | #endregion Packet Sending | ||
4485 | |||
4486 | #region Handle deleted objects | ||
4487 | if (m_killRecord.Count > 0) | ||
4488 | { | ||
4489 | SendKillObject(m_killRecord); | ||
4490 | m_killRecord.Clear(); | ||
4491 | } | ||
4492 | |||
4493 | if(GroupsNeedFullUpdate.Count > 0) | ||
4494 | { | ||
4495 | foreach(SceneObjectGroup grp in GroupsNeedFullUpdate) | ||
4202 | { | 4496 | { |
4203 | List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; | 4497 | foreach(SceneObjectPart p in grp.Parts) |
4204 | 4498 | SendEntityUpdate(p,PrimUpdateFlags.CancelKill); | |
4205 | ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | 4499 | lock(GroupsInView) |
4206 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | 4500 | GroupsInView.Add(grp); |
4207 | packet.RegionData.TimeDilation = timeDilation; | ||
4208 | packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
4209 | |||
4210 | for (int i = 0; i < blocks.Count; i++) | ||
4211 | packet.ObjectData[i] = blocks[i]; | ||
4212 | // If any of the packets created from this call go unacknowledged, all of the updates will be resent | ||
4213 | OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); }); | ||
4214 | } | 4501 | } |
4215 | 4502 | } | |
4216 | if (compressedUpdateBlocks.IsValueCreated) | 4503 | #endregion |
4504 | } | ||
4505 | |||
4506 | // hack.. dont use | ||
4507 | /* | ||
4508 | public void SendPartFullUpdate(ISceneEntity ent, uint? parentID) | ||
4509 | { | ||
4510 | if (ent is SceneObjectPart) | ||
4511 | { | ||
4512 | SceneObjectPart part = (SceneObjectPart)ent; | ||
4513 | ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | ||
4514 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
4515 | packet.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); | ||
4516 | packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | ||
4517 | |||
4518 | ObjectUpdatePacket.ObjectDataBlock blk = CreatePrimUpdateBlock(part, mysp); | ||
4519 | if (parentID.HasValue) | ||
4217 | { | 4520 | { |
4218 | List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value; | 4521 | blk.ParentID = parentID.Value; |
4219 | |||
4220 | ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); | ||
4221 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | ||
4222 | packet.RegionData.TimeDilation = timeDilation; | ||
4223 | packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count]; | ||
4224 | |||
4225 | for (int i = 0; i < blocks.Count; i++) | ||
4226 | packet.ObjectData[i] = blocks[i]; | ||
4227 | // If any of the packets created from this call go unacknowledged, all of the updates will be resent | ||
4228 | OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); }); | ||
4229 | } | 4522 | } |
4230 | 4523 | ||
4231 | if (terseUpdateBlocks.IsValueCreated) | 4524 | packet.ObjectData[0] = blk; |
4232 | { | ||
4233 | List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; | ||
4234 | |||
4235 | ImprovedTerseObjectUpdatePacket packet | ||
4236 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( | ||
4237 | PacketType.ImprovedTerseObjectUpdate); | ||
4238 | 4525 | ||
4239 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; | 4526 | OutPacket(packet, ThrottleOutPacketType.Task, true); |
4240 | packet.RegionData.TimeDilation = timeDilation; | ||
4241 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; | ||
4242 | |||
4243 | for (int i = 0; i < blocks.Count; i++) | ||
4244 | packet.ObjectData[i] = blocks[i]; | ||
4245 | // If any of the packets created from this call go unacknowledged, all of the updates will be resent | ||
4246 | OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); | ||
4247 | } | ||
4248 | } | 4527 | } |
4249 | 4528 | ||
4250 | // m_log.DebugFormat( | 4529 | // m_log.DebugFormat( |
4251 | // "[LLCLIENTVIEW]: Sent {0} updates in ProcessEntityUpdates() for {1} {2} in {3}", | 4530 | // "[LLCLIENTVIEW]: Sent {0} updates in ProcessEntityUpdates() for {1} {2} in {3}", |
4252 | // updatesThisCall, Name, SceneAgent.IsChildAgent ? "child" : "root", Scene.Name); | 4531 | // updatesThisCall, Name, SceneAgent.IsChildAgent ? "child" : "root", Scene.Name); |
4253 | // | 4532 | // |
4254 | #endregion Packet Sending | ||
4255 | } | 4533 | } |
4256 | 4534 | */ | |
4257 | public void ReprioritizeUpdates() | 4535 | public void ReprioritizeUpdates() |
4258 | { | 4536 | { |
4259 | lock (m_entityUpdates.SyncRoot) | 4537 | lock (m_entityUpdates.SyncRoot) |
4260 | m_entityUpdates.Reprioritize(UpdatePriorityHandler); | 4538 | m_entityUpdates.Reprioritize(UpdatePriorityHandler); |
4539 | CheckGroupsInView(); | ||
4540 | } | ||
4541 | |||
4542 | private bool CheckGroupsInViewBusy = false; | ||
4543 | |||
4544 | public void CheckGroupsInView() | ||
4545 | { | ||
4546 | bool doCulling = m_scene.ObjectsCullingByDistance; | ||
4547 | if(!doCulling) | ||
4548 | return; | ||
4549 | |||
4550 | if(CheckGroupsInViewBusy) | ||
4551 | return; | ||
4552 | |||
4553 | CheckGroupsInViewBusy = true; | ||
4554 | |||
4555 | float cullingrange = 64.0f; | ||
4556 | // Vector3 mycamera = Vector3.Zero; | ||
4557 | Vector3 mypos = Vector3.Zero; | ||
4558 | ScenePresence mysp = (ScenePresence)SceneAgent; | ||
4559 | if(mysp != null && !mysp.IsDeleted) | ||
4560 | { | ||
4561 | cullingrange = mysp.DrawDistance + m_scene.ReprioritizationDistance + 16f; | ||
4562 | // mycamera = mysp.CameraPosition; | ||
4563 | mypos = mysp.AbsolutePosition; | ||
4564 | } | ||
4565 | else | ||
4566 | { | ||
4567 | CheckGroupsInViewBusy= false; | ||
4568 | return; | ||
4569 | } | ||
4570 | |||
4571 | HashSet<SceneObjectGroup> NewGroupsInView = new HashSet<SceneObjectGroup>(); | ||
4572 | HashSet<SceneObjectGroup> GroupsNeedFullUpdate = new HashSet<SceneObjectGroup>(); | ||
4573 | List<SceneObjectGroup> kills = new List<SceneObjectGroup>(); | ||
4574 | |||
4575 | EntityBase[] entities = m_scene.Entities.GetEntities(); | ||
4576 | foreach (EntityBase e in entities) | ||
4577 | { | ||
4578 | if(!IsActive) | ||
4579 | return; | ||
4580 | |||
4581 | if (e != null && e is SceneObjectGroup) | ||
4582 | { | ||
4583 | SceneObjectGroup grp = (SceneObjectGroup)e; | ||
4584 | if(grp.IsDeleted || grp.IsAttachment) | ||
4585 | continue; | ||
4586 | |||
4587 | float bradius = grp.GetBoundsRadius(); | ||
4588 | Vector3 grppos = grp.AbsolutePosition + grp.getBoundsCenter(); | ||
4589 | // float dcam = (grppos - mycamera).LengthSquared(); | ||
4590 | float dpos = (grppos - mypos).LengthSquared(); | ||
4591 | // if(dcam < dpos) | ||
4592 | // dpos = dcam; | ||
4593 | |||
4594 | dpos = (float)Math.Sqrt(dpos) - bradius; | ||
4595 | |||
4596 | bool inview; | ||
4597 | lock(GroupsInView) | ||
4598 | inview = GroupsInView.Contains(grp); | ||
4599 | |||
4600 | if(dpos > cullingrange) | ||
4601 | { | ||
4602 | if(inview) | ||
4603 | kills.Add(grp); | ||
4604 | } | ||
4605 | else | ||
4606 | { | ||
4607 | if(!inview) | ||
4608 | GroupsNeedFullUpdate.Add(grp); | ||
4609 | NewGroupsInView.Add(grp); | ||
4610 | } | ||
4611 | } | ||
4612 | } | ||
4613 | |||
4614 | lock(GroupsInView) | ||
4615 | GroupsInView = NewGroupsInView; | ||
4616 | |||
4617 | if (kills.Count > 0) | ||
4618 | { | ||
4619 | List<uint> partIDs = new List<uint>(); | ||
4620 | foreach(SceneObjectGroup grp in kills) | ||
4621 | { | ||
4622 | SendEntityUpdate(grp.RootPart,PrimUpdateFlags.Kill); | ||
4623 | foreach(SceneObjectPart p in grp.Parts) | ||
4624 | { | ||
4625 | if(p != grp.RootPart) | ||
4626 | partIDs.Add(p.LocalId); | ||
4627 | } | ||
4628 | } | ||
4629 | kills.Clear(); | ||
4630 | if(partIDs.Count > 0) | ||
4631 | { | ||
4632 | lock (m_entityProps.SyncRoot) | ||
4633 | m_entityProps.Remove(partIDs); | ||
4634 | lock (m_entityUpdates.SyncRoot) | ||
4635 | m_entityUpdates.Remove(partIDs); | ||
4636 | } | ||
4637 | } | ||
4638 | |||
4639 | if(GroupsNeedFullUpdate.Count > 0) | ||
4640 | { | ||
4641 | foreach(SceneObjectGroup grp in GroupsNeedFullUpdate) | ||
4642 | { | ||
4643 | foreach(SceneObjectPart p in grp.Parts) | ||
4644 | SendEntityUpdate(p,PrimUpdateFlags.CancelKill); | ||
4645 | } | ||
4646 | } | ||
4647 | |||
4648 | CheckGroupsInViewBusy = false; | ||
4261 | } | 4649 | } |
4262 | 4650 | ||
4263 | private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity) | 4651 | private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity) |
@@ -4285,63 +4673,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4285 | // of updates converted to packets. Since we don't want packets | 4673 | // of updates converted to packets. Since we don't want packets |
4286 | // to sit in the queue with old data, only convert enough updates | 4674 | // to sit in the queue with old data, only convert enough updates |
4287 | // to packets that can be sent in 200ms. | 4675 | // to packets that can be sent in 200ms. |
4288 | private Int32 m_LastQueueFill = 0; | 4676 | // private Int32 m_LastQueueFill = 0; |
4289 | private Int32 m_maxUpdates = 0; | 4677 | // private Int32 m_maxUpdates = 0; |
4290 | 4678 | ||
4291 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) | 4679 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) |
4292 | { | 4680 | { |
4293 | // if (!m_udpServer.IsRunningOutbound) | 4681 | if(m_scene == null) |
4294 | // return; | 4682 | return; |
4295 | 4683 | ||
4296 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | 4684 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) |
4297 | { | 4685 | { |
4298 | // if (!m_udpServer.IsRunningOutbound) | 4686 | int maxUpdateBytes = m_udpClient.GetCatBytesCanSend(ThrottleOutPacketType.Task, 30); |
4299 | // return; | ||
4300 | 4687 | ||
4301 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) | ||
4302 | { | ||
4303 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; | ||
4304 | } | ||
4305 | else | ||
4306 | { | ||
4307 | if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) | ||
4308 | m_maxUpdates += 5; | ||
4309 | else | ||
4310 | m_maxUpdates = m_maxUpdates >> 1; | ||
4311 | } | ||
4312 | m_maxUpdates = Util.Clamp<Int32>(m_maxUpdates,10,500); | ||
4313 | m_LastQueueFill = Util.EnvironmentTickCount(); | ||
4314 | |||
4315 | if (m_entityUpdates.Count > 0) | 4688 | if (m_entityUpdates.Count > 0) |
4316 | ProcessEntityUpdates(m_maxUpdates); | 4689 | ProcessEntityUpdates(maxUpdateBytes); |
4317 | 4690 | ||
4318 | if (m_entityProps.Count > 0) | 4691 | if (m_entityProps.Count > 0) |
4319 | ProcessEntityPropertyRequests(m_maxUpdates); | 4692 | ProcessEntityPropertyRequests(maxUpdateBytes); |
4320 | } | 4693 | } |
4321 | 4694 | ||
4322 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) | 4695 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) |
4323 | ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); | 4696 | ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); |
4324 | } | 4697 | } |
4325 | 4698 | ||
4326 | internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories) | 4699 | internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories) |
4327 | { | 4700 | { |
4328 | bool hasUpdates = false; | ||
4329 | |||
4330 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | 4701 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) |
4331 | { | 4702 | { |
4332 | if (m_entityUpdates.Count > 0) | 4703 | if (m_entityUpdates.Count > 0) |
4333 | hasUpdates = true; | 4704 | return true; |
4334 | else if (m_entityProps.Count > 0) | 4705 | if (m_entityProps.Count > 0) |
4335 | hasUpdates = true; | 4706 | return true; |
4336 | } | 4707 | } |
4337 | 4708 | ||
4338 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) | 4709 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) |
4339 | { | 4710 | { |
4340 | if (ImageManager.HasUpdates()) | 4711 | if (ImageManager.HasUpdates()) |
4341 | hasUpdates = true; | 4712 | return true; |
4342 | } | 4713 | } |
4343 | 4714 | ||
4344 | return hasUpdates; | 4715 | return false; |
4345 | } | 4716 | } |
4346 | 4717 | ||
4347 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) | 4718 | public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) |
@@ -4443,13 +4814,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4443 | OutPacket(pack, ThrottleOutPacketType.Task); | 4814 | OutPacket(pack, ThrottleOutPacketType.Task); |
4444 | } | 4815 | } |
4445 | 4816 | ||
4446 | private class ObjectPropertyUpdate : IEntityUpdate | 4817 | private class ObjectPropertyUpdate : EntityUpdate |
4447 | { | 4818 | { |
4448 | internal bool SendFamilyProps; | 4819 | internal bool SendFamilyProps; |
4449 | internal bool SendObjectProps; | 4820 | internal bool SendObjectProps; |
4450 | 4821 | ||
4451 | public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj) | 4822 | public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj) |
4452 | : base(entity,flags) | 4823 | : base(entity,(PrimUpdateFlags)flags) |
4453 | { | 4824 | { |
4454 | SendFamilyProps = sendfam; | 4825 | SendFamilyProps = sendfam; |
4455 | SendObjectProps = sendobj; | 4826 | SendObjectProps = sendobj; |
@@ -4462,7 +4833,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4462 | base.Update(update); | 4833 | base.Update(update); |
4463 | } | 4834 | } |
4464 | } | 4835 | } |
4465 | 4836 | ||
4466 | public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) | 4837 | public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) |
4467 | { | 4838 | { |
4468 | uint priority = 0; // time based ordering only | 4839 | uint priority = 0; // time based ordering only |
@@ -4496,7 +4867,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4496 | foreach (ObjectPropertyUpdate update in updates) | 4867 | foreach (ObjectPropertyUpdate update in updates) |
4497 | ResendPropertyUpdate(update); | 4868 | ResendPropertyUpdate(update); |
4498 | } | 4869 | } |
4499 | 4870 | ||
4500 | public void SendObjectPropertiesReply(ISceneEntity entity) | 4871 | public void SendObjectPropertiesReply(ISceneEntity entity) |
4501 | { | 4872 | { |
4502 | uint priority = 0; // time based ordering only | 4873 | uint priority = 0; // time based ordering only |
@@ -4504,29 +4875,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4504 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); | 4875 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); |
4505 | } | 4876 | } |
4506 | 4877 | ||
4507 | private void ProcessEntityPropertyRequests(int maxUpdates) | 4878 | List<ObjectPropertiesFamilyPacket.ObjectDataBlock> objectFamilyBlocks = new |
4879 | List<ObjectPropertiesFamilyPacket.ObjectDataBlock>(); | ||
4880 | List<ObjectPropertiesPacket.ObjectDataBlock> objectPropertiesBlocks = | ||
4881 | new List<ObjectPropertiesPacket.ObjectDataBlock>(); | ||
4882 | List<SceneObjectPart> needPhysics = new List<SceneObjectPart>(); | ||
4883 | |||
4884 | private void ProcessEntityPropertyRequests(int maxUpdateBytes) | ||
4508 | { | 4885 | { |
4509 | OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>> objectFamilyBlocks = | 4886 | // OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates = |
4510 | new OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>>(); | 4887 | // new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>(); |
4511 | 4888 | ||
4512 | OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = | 4889 | // OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates = |
4513 | new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); | 4890 | // new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>(); |
4514 | 4891 | ||
4515 | OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates = | 4892 | bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance; |
4516 | new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>(); | ||
4517 | 4893 | ||
4518 | OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates = | 4894 | EntityUpdate iupdate; |
4519 | new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>(); | ||
4520 | |||
4521 | IEntityUpdate iupdate; | ||
4522 | Int32 timeinqueue; // this is just debugging code & can be dropped later | 4895 | Int32 timeinqueue; // this is just debugging code & can be dropped later |
4523 | 4896 | ||
4524 | int updatesThisCall = 0; | 4897 | while (maxUpdateBytes > 0) |
4525 | while (updatesThisCall < m_maxUpdates) | ||
4526 | { | 4898 | { |
4527 | lock (m_entityProps.SyncRoot) | 4899 | lock (m_entityProps.SyncRoot) |
4528 | if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) | 4900 | { |
4529 | break; | 4901 | if(orderedDequeue) |
4902 | { | ||
4903 | if (!m_entityProps.TryOrderedDequeue(out iupdate, out timeinqueue)) | ||
4904 | break; | ||
4905 | } | ||
4906 | else | ||
4907 | { | ||
4908 | if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) | ||
4909 | break; | ||
4910 | } | ||
4911 | } | ||
4530 | 4912 | ||
4531 | ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate; | 4913 | ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate; |
4532 | if (update.SendFamilyProps) | 4914 | if (update.SendFamilyProps) |
@@ -4535,8 +4917,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4535 | { | 4917 | { |
4536 | SceneObjectPart sop = (SceneObjectPart)update.Entity; | 4918 | SceneObjectPart sop = (SceneObjectPart)update.Entity; |
4537 | ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); | 4919 | ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); |
4538 | objectFamilyBlocks.Value.Add(objPropDB); | 4920 | objectFamilyBlocks.Add(objPropDB); |
4539 | familyUpdates.Value.Add(update); | 4921 | // familyUpdates.Value.Add(update); |
4922 | maxUpdateBytes -= objPropDB.Length; | ||
4540 | } | 4923 | } |
4541 | } | 4924 | } |
4542 | 4925 | ||
@@ -4545,84 +4928,107 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4545 | if (update.Entity is SceneObjectPart) | 4928 | if (update.Entity is SceneObjectPart) |
4546 | { | 4929 | { |
4547 | SceneObjectPart sop = (SceneObjectPart)update.Entity; | 4930 | SceneObjectPart sop = (SceneObjectPart)update.Entity; |
4931 | needPhysics.Add(sop); | ||
4548 | ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); | 4932 | ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); |
4549 | objectPropertiesBlocks.Value.Add(objPropDB); | 4933 | objectPropertiesBlocks.Add(objPropDB); |
4550 | propertyUpdates.Value.Add(update); | 4934 | // propertyUpdates.Value.Add(update); |
4935 | maxUpdateBytes -= objPropDB.Length; | ||
4551 | } | 4936 | } |
4552 | } | 4937 | } |
4553 | |||
4554 | updatesThisCall++; | ||
4555 | } | 4938 | } |
4556 | |||
4557 | 4939 | ||
4558 | // Int32 ppcnt = 0; | 4940 | if (objectPropertiesBlocks.Count > 0) |
4559 | // Int32 pbcnt = 0; | ||
4560 | |||
4561 | if (objectPropertiesBlocks.IsValueCreated) | ||
4562 | { | 4941 | { |
4563 | List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value; | ||
4564 | List<ObjectPropertyUpdate> updates = propertyUpdates.Value; | ||
4565 | |||
4566 | ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | 4942 | ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); |
4567 | packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; | 4943 | packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[objectPropertiesBlocks.Count]; |
4568 | for (int i = 0; i < blocks.Count; i++) | 4944 | for (int i = 0; i < objectPropertiesBlocks.Count; i++) |
4569 | packet.ObjectData[i] = blocks[i]; | 4945 | packet.ObjectData[i] = objectPropertiesBlocks[i]; |
4570 | 4946 | ||
4947 | |||
4948 | objectPropertiesBlocks.Clear(); | ||
4571 | packet.Header.Zerocoded = true; | 4949 | packet.Header.Zerocoded = true; |
4572 | 4950 | ||
4573 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties | 4951 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties |
4574 | // of the object rather than the properties when the packet was created | 4952 | // of the object rather than the properties when the packet was created |
4575 | OutPacket(packet, ThrottleOutPacketType.Task, true, | 4953 | // HACK : Remove intelligent resending until it's fixed in core |
4576 | delegate(OutgoingPacket oPacket) | 4954 | //OutPacket(packet, ThrottleOutPacketType.Task, true, |
4577 | { | 4955 | // delegate(OutgoingPacket oPacket) |
4578 | ResendPropertyUpdates(updates, oPacket); | 4956 | // { |
4579 | }); | 4957 | // ResendPropertyUpdates(propertyUpdates.Value, oPacket); |
4958 | // }); | ||
4959 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
4580 | 4960 | ||
4581 | // pbcnt += blocks.Count; | 4961 | // pbcnt += blocks.Count; |
4582 | // ppcnt++; | 4962 | // ppcnt++; |
4583 | } | 4963 | } |
4584 | 4964 | ||
4585 | // Int32 fpcnt = 0; | 4965 | // Int32 fpcnt = 0; |
4586 | // Int32 fbcnt = 0; | 4966 | // Int32 fbcnt = 0; |
4587 | 4967 | ||
4588 | if (objectFamilyBlocks.IsValueCreated) | 4968 | if (objectFamilyBlocks.Count > 0) |
4589 | { | 4969 | { |
4590 | List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value; | ||
4591 | |||
4592 | // one packet per object block... uggh... | 4970 | // one packet per object block... uggh... |
4593 | for (int i = 0; i < blocks.Count; i++) | 4971 | for (int i = 0; i < objectFamilyBlocks.Count; i++) |
4594 | { | 4972 | { |
4595 | ObjectPropertiesFamilyPacket packet = | 4973 | ObjectPropertiesFamilyPacket packet = |
4596 | (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); | 4974 | (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); |
4597 | 4975 | ||
4598 | packet.ObjectData = blocks[i]; | 4976 | packet.ObjectData = objectFamilyBlocks[i]; |
4599 | packet.Header.Zerocoded = true; | 4977 | packet.Header.Zerocoded = true; |
4600 | 4978 | ||
4601 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties | 4979 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties |
4602 | // of the object rather than the properties when the packet was created | 4980 | // of the object rather than the properties when the packet was created |
4603 | List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); | 4981 | // List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); |
4604 | updates.Add(familyUpdates.Value[i]); | 4982 | // updates.Add(familyUpdates.Value[i]); |
4605 | OutPacket(packet, ThrottleOutPacketType.Task, true, | 4983 | // HACK : Remove intelligent resending until it's fixed in core |
4606 | delegate(OutgoingPacket oPacket) | 4984 | //OutPacket(packet, ThrottleOutPacketType.Task, true, |
4607 | { | 4985 | // delegate(OutgoingPacket oPacket) |
4608 | ResendPropertyUpdates(updates, oPacket); | 4986 | // { |
4609 | }); | 4987 | // ResendPropertyUpdates(updates, oPacket); |
4988 | // }); | ||
4989 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
4610 | 4990 | ||
4611 | // fpcnt++; | 4991 | // fpcnt++; |
4612 | // fbcnt++; | 4992 | // fbcnt++; |
4613 | } | 4993 | } |
4614 | 4994 | objectFamilyBlocks.Clear(); | |
4995 | } | ||
4996 | |||
4997 | if(needPhysics.Count > 0) | ||
4998 | { | ||
4999 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); | ||
5000 | if(eq != null) | ||
5001 | { | ||
5002 | OSDArray array = new OSDArray(); | ||
5003 | foreach(SceneObjectPart sop in needPhysics) | ||
5004 | { | ||
5005 | OSDMap physinfo = new OSDMap(6); | ||
5006 | physinfo["LocalID"] = sop.LocalId; | ||
5007 | physinfo["Density"] = sop.Density; | ||
5008 | physinfo["Friction"] = sop.Friction; | ||
5009 | physinfo["GravityMultiplier"] = sop.GravityModifier; | ||
5010 | physinfo["Restitution"] = sop.Restitution; | ||
5011 | physinfo["PhysicsShapeType"] = (int)sop.PhysicsShapeType; | ||
5012 | array.Add(physinfo); | ||
5013 | } | ||
5014 | |||
5015 | OSDMap llsdBody = new OSDMap(1); | ||
5016 | llsdBody.Add("ObjectData", array); | ||
5017 | |||
5018 | eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId); | ||
5019 | } | ||
5020 | needPhysics.Clear(); | ||
4615 | } | 5021 | } |
4616 | 5022 | ||
4617 | // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); | 5023 | // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); |
4618 | // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); | 5024 | // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); |
4619 | } | 5025 | } |
4620 | 5026 | ||
4621 | private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) | 5027 | private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, PrimUpdateFlags requestFlags) |
4622 | { | 5028 | { |
4623 | ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); | 5029 | ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); |
4624 | 5030 | ||
4625 | block.RequestFlags = requestFlags; | 5031 | block.RequestFlags = (uint)requestFlags; |
4626 | block.ObjectID = sop.UUID; | 5032 | block.ObjectID = sop.UUID; |
4627 | if (sop.OwnerID == sop.GroupID) | 5033 | if (sop.OwnerID == sop.GroupID) |
4628 | block.OwnerID = UUID.Zero; | 5034 | block.OwnerID = UUID.Zero; |
@@ -4640,13 +5046,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4640 | block.SaleType = sop.ObjectSaleType; | 5046 | block.SaleType = sop.ObjectSaleType; |
4641 | block.SalePrice = sop.SalePrice; | 5047 | block.SalePrice = sop.SalePrice; |
4642 | block.Category = sop.Category; | 5048 | block.Category = sop.Category; |
4643 | block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right? | 5049 | block.LastOwnerID = sop.LastOwnerID; |
4644 | block.Name = Util.StringToBytes256(sop.Name); | 5050 | block.Name = Util.StringToBytes256(sop.Name); |
4645 | block.Description = Util.StringToBytes256(sop.Description); | 5051 | block.Description = Util.StringToBytes256(sop.Description); |
4646 | 5052 | ||
4647 | return block; | 5053 | return block; |
4648 | } | 5054 | } |
4649 | 5055 | ||
4650 | private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) | 5056 | private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) |
4651 | { | 5057 | { |
4652 | //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | 5058 | //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); |
@@ -4672,7 +5078,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4672 | block.FolderID = UUID.Zero; // sog.FromFolderID ?? | 5078 | block.FolderID = UUID.Zero; // sog.FromFolderID ?? |
4673 | block.FromTaskID = UUID.Zero; // ??? | 5079 | block.FromTaskID = UUID.Zero; // ??? |
4674 | block.InventorySerial = (short)sop.InventorySerial; | 5080 | block.InventorySerial = (short)sop.InventorySerial; |
4675 | 5081 | ||
4676 | SceneObjectPart root = sop.ParentGroup.RootPart; | 5082 | SceneObjectPart root = sop.ParentGroup.RootPart; |
4677 | 5083 | ||
4678 | block.TouchName = Util.StringToBytes256(root.TouchName); | 5084 | block.TouchName = Util.StringToBytes256(root.TouchName); |
@@ -4684,7 +5090,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4684 | // { | 5090 | // { |
4685 | // using (BinaryWriter binWriter = new BinaryWriter(memStream)) | 5091 | // using (BinaryWriter binWriter = new BinaryWriter(memStream)) |
4686 | // { | 5092 | // { |
4687 | // for (int i = 0; i < sop.GetNumberOfSides(); i++) | 5093 | // for (int i = 0; i < sop.GetNumberOfSides(); i++) |
4688 | // { | 5094 | // { |
4689 | // Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i]; | 5095 | // Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i]; |
4690 | // | 5096 | // |
@@ -4701,7 +5107,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4701 | // block.TextureID = memStream.ToArray(); | 5107 | // block.TextureID = memStream.ToArray(); |
4702 | // } | 5108 | // } |
4703 | // } | 5109 | // } |
4704 | 5110 | ||
4705 | block.TextureID = new byte[0]; // TextureID ??? | 5111 | block.TextureID = new byte[0]; // TextureID ??? |
4706 | block.SitName = Util.StringToBytes256(root.SitName); | 5112 | block.SitName = Util.StringToBytes256(root.SitName); |
4707 | block.OwnerMask = root.OwnerMask; | 5113 | block.OwnerMask = root.OwnerMask; |
@@ -4728,52 +5134,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4728 | } | 5134 | } |
4729 | 5135 | ||
4730 | public void SendEstateList(UUID invoice, int code, UUID[] Data, uint estateID) | 5136 | public void SendEstateList(UUID invoice, int code, UUID[] Data, uint estateID) |
4731 | |||
4732 | { | 5137 | { |
4733 | EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); | 5138 | int TotalnumberIDs = Data.Length; |
4734 | packet.AgentData.TransactionID = UUID.Random(); | 5139 | int numberIDs; |
4735 | packet.AgentData.AgentID = AgentId; | 5140 | int IDIndex = 0; |
4736 | packet.AgentData.SessionID = SessionId; | ||
4737 | packet.MethodData.Invoice = invoice; | ||
4738 | packet.MethodData.Method = Utils.StringToBytes("setaccess"); | ||
4739 | 5141 | ||
4740 | EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + Data.Length]; | 5142 | do |
4741 | |||
4742 | for (int i = 0; i < (6 + Data.Length); i++) | ||
4743 | { | 5143 | { |
4744 | returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock(); | 5144 | if(TotalnumberIDs > 63) |
4745 | } | 5145 | numberIDs = 63; |
4746 | int j = 0; | 5146 | else |
5147 | numberIDs = TotalnumberIDs; | ||
4747 | 5148 | ||
4748 | returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++; | 5149 | TotalnumberIDs -= numberIDs; |
4749 | returnblock[j].Parameter = Utils.StringToBytes(code.ToString()); j++; | ||
4750 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4751 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4752 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4753 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4754 | 5150 | ||
4755 | j = 2; // Agents | 5151 | EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); |
4756 | if ((code & 2) != 0) | 5152 | packet.AgentData.TransactionID = UUID.Random(); |
4757 | j = 3; // Groups | 5153 | packet.AgentData.AgentID = AgentId; |
4758 | if ((code & 8) != 0) | 5154 | packet.AgentData.SessionID = SessionId; |
4759 | j = 5; // Managers | 5155 | packet.MethodData.Invoice = invoice; |
5156 | packet.MethodData.Method = Utils.StringToBytes("setaccess"); | ||
4760 | 5157 | ||
4761 | returnblock[j].Parameter = Utils.StringToBytes(Data.Length.ToString()); | 5158 | EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + numberIDs]; |
4762 | j = 6; | ||
4763 | 5159 | ||
4764 | for (int i = 0; i < Data.Length; i++) | 5160 | for (int i = 0; i < (6 + numberIDs); i++) |
4765 | { | 5161 | { |
4766 | returnblock[j].Parameter = Data[i].GetBytes(); j++; | 5162 | returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock(); |
4767 | } | 5163 | } |
4768 | packet.ParamList = returnblock; | 5164 | |
4769 | packet.Header.Reliable = true; | 5165 | returnblock[0].Parameter = Utils.StringToBytes(estateID.ToString()); |
4770 | OutPacket(packet, ThrottleOutPacketType.Task); | 5166 | returnblock[1].Parameter = Utils.StringToBytes(code.ToString()); |
5167 | |||
5168 | if((code & 1) != 0) // allowagents | ||
5169 | returnblock[2].Parameter = Utils.StringToBytes(numberIDs.ToString()); | ||
5170 | else | ||
5171 | returnblock[2].Parameter = Utils.StringToBytes("0"); | ||
5172 | |||
5173 | if((code & 2) != 0) // groups | ||
5174 | returnblock[3].Parameter = Utils.StringToBytes(numberIDs.ToString()); | ||
5175 | else | ||
5176 | returnblock[3].Parameter = Utils.StringToBytes("0"); | ||
5177 | |||
5178 | if((code & 4) != 0) // bans | ||
5179 | returnblock[4].Parameter = Utils.StringToBytes(numberIDs.ToString()); | ||
5180 | else | ||
5181 | returnblock[4].Parameter = Utils.StringToBytes("0"); | ||
5182 | |||
5183 | if((code & 8) != 0) // managers | ||
5184 | returnblock[5].Parameter = Utils.StringToBytes(numberIDs.ToString()); | ||
5185 | else | ||
5186 | returnblock[5].Parameter = Utils.StringToBytes("0"); | ||
5187 | |||
5188 | int j = 6; | ||
5189 | |||
5190 | for (int i = 0; i < numberIDs; i++) | ||
5191 | { | ||
5192 | returnblock[j].Parameter = Data[IDIndex].GetBytes(); | ||
5193 | j++; | ||
5194 | IDIndex++; | ||
5195 | } | ||
5196 | packet.ParamList = returnblock; | ||
5197 | packet.Header.Reliable = true; | ||
5198 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
5199 | } while (TotalnumberIDs > 0); | ||
4771 | } | 5200 | } |
4772 | 5201 | ||
4773 | public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID) | 5202 | public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID) |
4774 | { | 5203 | { |
4775 | List<UUID> BannedUsers = new List<UUID>(); | 5204 | List<UUID> BannedUsers = new List<UUID>(); |
4776 | |||
4777 | for (int i = 0; i < bl.Length; i++) | 5205 | for (int i = 0; i < bl.Length; i++) |
4778 | { | 5206 | { |
4779 | if (bl[i] == null) | 5207 | if (bl[i] == null) |
@@ -4781,44 +5209,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4781 | if (bl[i].BannedUserID == UUID.Zero) | 5209 | if (bl[i].BannedUserID == UUID.Zero) |
4782 | continue; | 5210 | continue; |
4783 | BannedUsers.Add(bl[i].BannedUserID); | 5211 | BannedUsers.Add(bl[i].BannedUserID); |
4784 | |||
4785 | if (BannedUsers.Count >= 50 || (i == (bl.Length - 1) && BannedUsers.Count > 0)) | ||
4786 | { | ||
4787 | EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); | ||
4788 | packet.AgentData.TransactionID = UUID.Random(); | ||
4789 | packet.AgentData.AgentID = AgentId; | ||
4790 | packet.AgentData.SessionID = SessionId; | ||
4791 | packet.MethodData.Invoice = invoice; | ||
4792 | packet.MethodData.Method = Utils.StringToBytes("setaccess"); | ||
4793 | |||
4794 | EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + BannedUsers.Count]; | ||
4795 | |||
4796 | int j; | ||
4797 | for (j = 0; j < (6 + BannedUsers.Count); j++) | ||
4798 | { | ||
4799 | returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock(); | ||
4800 | } | ||
4801 | j = 0; | ||
4802 | |||
4803 | returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++; | ||
4804 | returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++; | ||
4805 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4806 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4807 | returnblock[j].Parameter = Utils.StringToBytes(BannedUsers.Count.ToString()); j++; | ||
4808 | returnblock[j].Parameter = Utils.StringToBytes("0"); j++; | ||
4809 | |||
4810 | foreach (UUID banned in BannedUsers) | ||
4811 | { | ||
4812 | returnblock[j].Parameter = banned.GetBytes(); j++; | ||
4813 | } | ||
4814 | packet.ParamList = returnblock; | ||
4815 | packet.Header.Reliable = true; | ||
4816 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
4817 | |||
4818 | BannedUsers.Clear(); | ||
4819 | } | ||
4820 | } | 5212 | } |
4821 | 5213 | SendEstateList(invoice, 4, BannedUsers.ToArray(), estateID); | |
4822 | } | 5214 | } |
4823 | 5215 | ||
4824 | public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args) | 5216 | public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args) |
@@ -4864,7 +5256,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4864 | public void SendEstateCovenantInformation(UUID covenant) | 5256 | public void SendEstateCovenantInformation(UUID covenant) |
4865 | { | 5257 | { |
4866 | // m_log.DebugFormat("[LLCLIENTVIEW]: Sending estate covenant asset id of {0} to {1}", covenant, Name); | 5258 | // m_log.DebugFormat("[LLCLIENTVIEW]: Sending estate covenant asset id of {0} to {1}", covenant, Name); |
4867 | 5259 | ||
4868 | EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket(); | 5260 | EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket(); |
4869 | EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock(); | 5261 | EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock(); |
4870 | edata.CovenantID = covenant; | 5262 | edata.CovenantID = covenant; |
@@ -4881,7 +5273,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4881 | { | 5273 | { |
4882 | // m_log.DebugFormat( | 5274 | // m_log.DebugFormat( |
4883 | // "[LLCLIENTVIEW]: Sending detailed estate data to {0} with covenant asset id {1}", Name, covenant); | 5275 | // "[LLCLIENTVIEW]: Sending detailed estate data to {0} with covenant asset id {1}", Name, covenant); |
4884 | 5276 | ||
4885 | EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); | 5277 | EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); |
4886 | packet.MethodData.Invoice = invoice; | 5278 | packet.MethodData.Invoice = invoice; |
4887 | packet.AgentData.TransactionID = UUID.Random(); | 5279 | packet.AgentData.TransactionID = UUID.Random(); |
@@ -4939,17 +5331,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4939 | packet.ParcelData.Data = data; | 5331 | packet.ParcelData.Data = data; |
4940 | packet.ParcelData.SequenceID = sequence_id; | 5332 | packet.ParcelData.SequenceID = sequence_id; |
4941 | packet.Header.Zerocoded = true; | 5333 | packet.Header.Zerocoded = true; |
4942 | OutPacket(packet, ThrottleOutPacketType.Task); | 5334 | // OutPacket(packet, ThrottleOutPacketType.Task); |
5335 | OutPacket(packet, ThrottleOutPacketType.Land); | ||
4943 | } | 5336 | } |
4944 | 5337 | ||
4945 | public void SendLandProperties( | 5338 | public void SendLandProperties( |
4946 | int sequence_id, bool snap_selection, int request_result, ILandObject lo, | 5339 | int sequence_id, bool snap_selection, int request_result, ILandObject lo, |
4947 | float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags) | 5340 | float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags) |
4948 | { | 5341 | { |
4949 | // m_log.DebugFormat("[LLCLIENTVIEW]: Sending land properties for {0} to {1}", lo.LandData.GlobalID, Name); | 5342 | // m_log.DebugFormat("[LLCLIENTVIEW]: Sending land properties for {0} to {1}", lo.LandData.GlobalID, Name); |
4950 | 5343 | ||
4951 | LandData landData = lo.LandData; | 5344 | LandData landData = lo.LandData; |
4952 | 5345 | ||
4953 | ParcelPropertiesMessage updateMessage = new ParcelPropertiesMessage(); | 5346 | ParcelPropertiesMessage updateMessage = new ParcelPropertiesMessage(); |
4954 | 5347 | ||
4955 | updateMessage.AABBMax = landData.AABBMax; | 5348 | updateMessage.AABBMax = landData.AABBMax; |
@@ -4962,7 +5355,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4962 | updateMessage.Category = landData.Category; | 5355 | updateMessage.Category = landData.Category; |
4963 | updateMessage.ClaimDate = Util.ToDateTime(landData.ClaimDate); | 5356 | updateMessage.ClaimDate = Util.ToDateTime(landData.ClaimDate); |
4964 | updateMessage.ClaimPrice = landData.ClaimPrice; | 5357 | updateMessage.ClaimPrice = landData.ClaimPrice; |
4965 | updateMessage.GroupID = landData.GroupID; | 5358 | updateMessage.GroupID = landData.GroupID; |
4966 | updateMessage.IsGroupOwned = landData.IsGroupOwned; | 5359 | updateMessage.IsGroupOwned = landData.IsGroupOwned; |
4967 | updateMessage.LandingType = (LandingType) landData.LandingType; | 5360 | updateMessage.LandingType = (LandingType) landData.LandingType; |
4968 | updateMessage.LocalID = landData.LocalID; | 5361 | updateMessage.LocalID = landData.LocalID; |
@@ -4983,7 +5376,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4983 | updateMessage.Name = landData.Name; | 5376 | updateMessage.Name = landData.Name; |
4984 | updateMessage.OtherCleanTime = landData.OtherCleanTime; | 5377 | updateMessage.OtherCleanTime = landData.OtherCleanTime; |
4985 | updateMessage.OtherCount = 0; //TODO: Unimplemented | 5378 | updateMessage.OtherCount = 0; //TODO: Unimplemented |
4986 | updateMessage.OwnerID = landData.OwnerID; | 5379 | updateMessage.OwnerID = landData.OwnerID; |
4987 | updateMessage.ParcelFlags = (ParcelFlags) landData.Flags; | 5380 | updateMessage.ParcelFlags = (ParcelFlags) landData.Flags; |
4988 | updateMessage.ParcelPrimBonus = simObjectBonusFactor; | 5381 | updateMessage.ParcelPrimBonus = simObjectBonusFactor; |
4989 | updateMessage.PassHours = landData.PassHours; | 5382 | updateMessage.PassHours = landData.PassHours; |
@@ -4998,20 +5391,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4998 | 5391 | ||
4999 | updateMessage.RentPrice = 0; | 5392 | updateMessage.RentPrice = 0; |
5000 | updateMessage.RequestResult = (ParcelResult) request_result; | 5393 | updateMessage.RequestResult = (ParcelResult) request_result; |
5001 | updateMessage.SalePrice = landData.SalePrice; | 5394 | updateMessage.SalePrice = landData.SalePrice; |
5002 | updateMessage.SelfCount = 0; //TODO: Unimplemented | 5395 | updateMessage.SelfCount = 0; //TODO: Unimplemented |
5003 | updateMessage.SequenceID = sequence_id; | 5396 | updateMessage.SequenceID = sequence_id; |
5004 | 5397 | ||
5005 | if (landData.SimwideArea > 0) | 5398 | if (landData.SimwideArea > 0) |
5006 | { | 5399 | { |
5007 | int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); | 5400 | updateMessage.SimWideMaxPrims = lo.GetSimulatorMaxPrimCount(); |
5008 | updateMessage.SimWideMaxPrims = simulatorCapacity; | ||
5009 | } | 5401 | } |
5010 | else | 5402 | else |
5011 | { | 5403 | { |
5012 | updateMessage.SimWideMaxPrims = 0; | 5404 | updateMessage.SimWideMaxPrims = 0; |
5013 | } | 5405 | } |
5014 | 5406 | ||
5015 | updateMessage.SnapSelection = snap_selection; | 5407 | updateMessage.SnapSelection = snap_selection; |
5016 | updateMessage.SnapshotID = landData.SnapshotID; | 5408 | updateMessage.SnapshotID = landData.SnapshotID; |
5017 | updateMessage.Status = (ParcelStatus) landData.Status; | 5409 | updateMessage.Status = (ParcelStatus) landData.Status; |
@@ -5025,23 +5417,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5025 | updateMessage.MediaLoop = landData.MediaLoop; | 5417 | updateMessage.MediaLoop = landData.MediaLoop; |
5026 | updateMessage.ObscureMusic = landData.ObscureMusic; | 5418 | updateMessage.ObscureMusic = landData.ObscureMusic; |
5027 | updateMessage.ObscureMedia = landData.ObscureMedia; | 5419 | updateMessage.ObscureMedia = landData.ObscureMedia; |
5028 | 5420 | ||
5421 | updateMessage.SeeAVs = landData.SeeAVs; | ||
5422 | updateMessage.AnyAVSounds = landData.AnyAVSounds; | ||
5423 | updateMessage.GroupAVSounds = landData.GroupAVSounds; | ||
5424 | |||
5029 | IPrimCounts pc = lo.PrimCounts; | 5425 | IPrimCounts pc = lo.PrimCounts; |
5030 | updateMessage.OwnerPrims = pc.Owner; | 5426 | updateMessage.OwnerPrims = pc.Owner; |
5031 | updateMessage.GroupPrims = pc.Group; | 5427 | updateMessage.GroupPrims = pc.Group; |
5032 | updateMessage.OtherPrims = pc.Others; | 5428 | updateMessage.OtherPrims = pc.Others; |
5033 | updateMessage.SelectedPrims = pc.Selected; | 5429 | updateMessage.SelectedPrims = pc.Selected; |
5034 | updateMessage.TotalPrims = pc.Total; | 5430 | updateMessage.TotalPrims = pc.Total; |
5035 | updateMessage.SimWideTotalPrims = pc.Simulator; | 5431 | updateMessage.SimWideTotalPrims = pc.Simulator; |
5036 | 5432 | ||
5433 | //m_log.DebugFormat("[YYY]: SimWideMaxPrims={0} OwnerPrims={1} TotalPrims={2} SimWideTotalPrims={3} MaxPrims={4}", | ||
5434 | // updateMessage.SimWideMaxPrims, updateMessage.OwnerPrims, updateMessage.TotalPrims, updateMessage.SimWideTotalPrims, updateMessage.MaxPrims); | ||
5037 | try | 5435 | try |
5038 | { | 5436 | { |
5039 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); | 5437 | IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); |
5040 | if (eq != null) | 5438 | if (eq != null) |
5041 | { | 5439 | { |
5042 | eq.ParcelProperties(updateMessage, this.AgentId); | 5440 | eq.ParcelProperties(updateMessage, this.AgentId); |
5043 | } | 5441 | } |
5044 | else | 5442 | else |
5045 | { | 5443 | { |
5046 | m_log.Warn("[LLCLIENTVIEW]: No EQ Interface when sending parcel data."); | 5444 | m_log.Warn("[LLCLIENTVIEW]: No EQ Interface when sending parcel data."); |
5047 | } | 5445 | } |
@@ -5078,7 +5476,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5078 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) | 5476 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) |
5079 | { | 5477 | { |
5080 | // m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); | 5478 | // m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); |
5081 | 5479 | ||
5082 | bool firstCall = true; | 5480 | bool firstCall = true; |
5083 | const int MAX_OBJECTS_PER_PACKET = 251; | 5481 | const int MAX_OBJECTS_PER_PACKET = 251; |
5084 | ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); | 5482 | ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); |
@@ -5133,14 +5531,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5133 | 5531 | ||
5134 | if (notifyCount > 0) | 5532 | if (notifyCount > 0) |
5135 | { | 5533 | { |
5136 | if (notifyCount > 32) | 5534 | // if (notifyCount > 32) |
5137 | { | 5535 | // { |
5138 | m_log.InfoFormat( | 5536 | // m_log.InfoFormat( |
5139 | "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" | 5537 | // "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" |
5140 | + " - a developer might want to investigate whether this is a hard limit", 32); | 5538 | // + " - a developer might want to investigate whether this is a hard limit", 32); |
5141 | 5539 | // | |
5142 | notifyCount = 32; | 5540 | // notifyCount = 32; |
5143 | } | 5541 | // } |
5144 | 5542 | ||
5145 | ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock | 5543 | ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock |
5146 | = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; | 5544 | = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; |
@@ -5178,6 +5576,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5178 | #endregion | 5576 | #endregion |
5179 | 5577 | ||
5180 | #region Helper Methods | 5578 | #region Helper Methods |
5579 | private void ClampVectorForUint(ref Vector3 v, float max) | ||
5580 | { | ||
5581 | float a,b; | ||
5582 | |||
5583 | a = Math.Abs(v.X); | ||
5584 | b = Math.Abs(v.Y); | ||
5585 | if(b > a) | ||
5586 | a = b; | ||
5587 | b= Math.Abs(v.Z); | ||
5588 | if(b > a) | ||
5589 | a = b; | ||
5590 | |||
5591 | if (a > max) | ||
5592 | { | ||
5593 | a = max / a; | ||
5594 | v.X *= a; | ||
5595 | v.Y *= a; | ||
5596 | v.Z *= a; | ||
5597 | } | ||
5598 | } | ||
5181 | 5599 | ||
5182 | protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity, bool sendTexture) | 5600 | protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity, bool sendTexture) |
5183 | { | 5601 | { |
@@ -5191,45 +5609,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5191 | Quaternion rotation; | 5609 | Quaternion rotation; |
5192 | byte[] textureEntry; | 5610 | byte[] textureEntry; |
5193 | 5611 | ||
5194 | if (entity is ScenePresence) | 5612 | if (avatar) |
5195 | { | 5613 | { |
5196 | ScenePresence presence = (ScenePresence)entity; | 5614 | ScenePresence presence = (ScenePresence)entity; |
5197 | 5615 | ||
5198 | // m_log.DebugFormat( | ||
5199 | // "[LLCLIENTVIEW]: Sending terse update to {0} with pos {1}, vel {2} in {3}", | ||
5200 | // Name, presence.OffsetPosition, presence.Velocity, m_scene.Name); | ||
5201 | |||
5202 | attachPoint = presence.State; | ||
5203 | collisionPlane = presence.CollisionPlane; | ||
5204 | position = presence.OffsetPosition; | 5616 | position = presence.OffsetPosition; |
5205 | velocity = presence.Velocity; | 5617 | velocity = presence.Velocity; |
5206 | acceleration = Vector3.Zero; | 5618 | acceleration = Vector3.Zero; |
5207 | |||
5208 | // Interestingly, sending this to non-zero will cause the client's avatar to start moving & accelerating | ||
5209 | // in that direction, even though we don't model this on the server. Implementing this in the future | ||
5210 | // may improve movement smoothness. | ||
5211 | // acceleration = new Vector3(1, 0, 0); | ||
5212 | |||
5213 | angularVelocity = presence.AngularVelocity; | ||
5214 | |||
5215 | // Whilst not in mouselook, an avatar will transmit only the Z rotation as this is the only axis | ||
5216 | // it rotates around. | ||
5217 | // In mouselook, X and Y co-ordinate will also be sent but when used in Rotation, these cause unwanted | ||
5218 | // excessive up and down movements of the camera when looking up and down. | ||
5219 | // See http://opensimulator.org/mantis/view.php?id=3274 | ||
5220 | // This does not affect head movement, since this is controlled entirely by camera movement rather than | ||
5221 | // body rotation. We still need to transmit X and Y for sitting avatars but mouselook does not change | ||
5222 | // the rotation in this case. | ||
5223 | rotation = presence.Rotation; | 5619 | rotation = presence.Rotation; |
5224 | 5620 | // tpvs can only see rotations around Z in some cases | |
5225 | if (!presence.IsSatOnObject) | 5621 | if(!presence.Flying && !presence.IsSatOnObject) |
5226 | { | 5622 | { |
5227 | rotation.X = 0; | 5623 | rotation.X = 0f; |
5228 | rotation.Y = 0; | 5624 | rotation.Y = 0f; |
5625 | rotation.Normalize(); | ||
5229 | } | 5626 | } |
5627 | angularVelocity = presence.AngularVelocity; | ||
5628 | |||
5629 | // m_log.DebugFormat( | ||
5630 | // "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name); | ||
5631 | |||
5632 | attachPoint = presence.State; | ||
5633 | collisionPlane = presence.CollisionPlane; | ||
5230 | 5634 | ||
5231 | if (sendTexture) | 5635 | if (sendTexture) |
5636 | { | ||
5232 | textureEntry = presence.Appearance.Texture.GetBytes(); | 5637 | textureEntry = presence.Appearance.Texture.GetBytes(); |
5638 | } | ||
5233 | else | 5639 | else |
5234 | textureEntry = null; | 5640 | textureEntry = null; |
5235 | } | 5641 | } |
@@ -5287,11 +5693,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5287 | pos += 12; | 5693 | pos += 12; |
5288 | 5694 | ||
5289 | // Velocity | 5695 | // Velocity |
5696 | ClampVectorForUint(ref velocity, 128f); | ||
5290 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.X, -128.0f, 128.0f), data, pos); pos += 2; | 5697 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.X, -128.0f, 128.0f), data, pos); pos += 2; |
5291 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Y, -128.0f, 128.0f), data, pos); pos += 2; | 5698 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Y, -128.0f, 128.0f), data, pos); pos += 2; |
5292 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Z, -128.0f, 128.0f), data, pos); pos += 2; | 5699 | Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Z, -128.0f, 128.0f), data, pos); pos += 2; |
5293 | 5700 | ||
5294 | // Acceleration | 5701 | // Acceleration |
5702 | ClampVectorForUint(ref acceleration, 64f); | ||
5295 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.X, -64.0f, 64.0f), data, pos); pos += 2; | 5703 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.X, -64.0f, 64.0f), data, pos); pos += 2; |
5296 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2; | 5704 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2; |
5297 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2; | 5705 | Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2; |
@@ -5303,13 +5711,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5303 | Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.W, -1.0f, 1.0f), data, pos); pos += 2; | 5711 | Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.W, -1.0f, 1.0f), data, pos); pos += 2; |
5304 | 5712 | ||
5305 | // Angular Velocity | 5713 | // Angular Velocity |
5714 | ClampVectorForUint(ref angularVelocity, 64f); | ||
5306 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2; | 5715 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2; |
5307 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; | 5716 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; |
5308 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; | 5717 | Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; |
5309 | 5718 | ||
5310 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block | 5719 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block |
5311 | = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); | 5720 | = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); |
5312 | 5721 | ||
5313 | block.Data = data; | 5722 | block.Data = data; |
5314 | 5723 | ||
5315 | if (textureEntry != null && textureEntry.Length > 0) | 5724 | if (textureEntry != null && textureEntry.Length > 0) |
@@ -5333,34 +5742,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5333 | 5742 | ||
5334 | protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) | 5743 | protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) |
5335 | { | 5744 | { |
5745 | Vector3 offsetPosition = data.OffsetPosition; | ||
5746 | Quaternion rotation = data.Rotation; | ||
5747 | uint parentID = data.ParentID; | ||
5748 | |||
5336 | // m_log.DebugFormat( | 5749 | // m_log.DebugFormat( |
5337 | // "[LLCLIENTVIEW]: Sending full update to {0} with pos {1}, vel {2} in {3}", Name, data.OffsetPosition, data.Velocity, m_scene.Name); | 5750 | // "[LLCLIENTVIEW]: Sending full update to {0} with pos {1}, vel {2} in {3}", Name, data.OffsetPosition, data.Velocity, m_scene.Name); |
5338 | 5751 | ||
5339 | byte[] objectData = new byte[76]; | 5752 | byte[] objectData = new byte[76]; |
5340 | 5753 | ||
5341 | data.CollisionPlane.ToBytes(objectData, 0); | 5754 | Vector3 velocity = new Vector3(0, 0, 0); |
5342 | data.OffsetPosition.ToBytes(objectData, 16); | 5755 | Vector3 acceleration = new Vector3(0, 0, 0); |
5343 | data.Velocity.ToBytes(objectData, 28); | 5756 | // tpvs can only see rotations around Z in some cases |
5344 | // data.Acceleration.ToBytes(objectData, 40); | 5757 | if(!data.Flying && !data.IsSatOnObject) |
5345 | |||
5346 | // Whilst not in mouselook, an avatar will transmit only the Z rotation as this is the only axis | ||
5347 | // it rotates around. | ||
5348 | // In mouselook, X and Y co-ordinate will also be sent but when used in Rotation, these cause unwanted | ||
5349 | // excessive up and down movements of the camera when looking up and down. | ||
5350 | // See http://opensimulator.org/mantis/view.php?id=3274 | ||
5351 | // This does not affect head movement, since this is controlled entirely by camera movement rather than | ||
5352 | // body rotation. We still need to transmit X and Y for sitting avatars but mouselook does not change | ||
5353 | // the rotation in this case. | ||
5354 | Quaternion rot = data.Rotation; | ||
5355 | |||
5356 | if (!data.IsSatOnObject) | ||
5357 | { | 5758 | { |
5358 | rot.X = 0; | 5759 | rotation.X = 0f; |
5359 | rot.Y = 0; | 5760 | rotation.Y = 0f; |
5360 | } | 5761 | } |
5762 | rotation.Normalize(); | ||
5361 | 5763 | ||
5362 | rot.ToBytes(objectData, 52); | 5764 | data.CollisionPlane.ToBytes(objectData, 0); |
5363 | //data.AngularVelocity.ToBytes(objectData, 64); | 5765 | offsetPosition.ToBytes(objectData, 16); |
5766 | velocity.ToBytes(objectData, 28); | ||
5767 | acceleration.ToBytes(objectData, 40); | ||
5768 | rotation.ToBytes(objectData, 52); | ||
5769 | data.AngularVelocity.ToBytes(objectData, 64); | ||
5364 | 5770 | ||
5365 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | 5771 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); |
5366 | 5772 | ||
@@ -5386,7 +5792,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5386 | update.PCode = (byte)PCode.Avatar; | 5792 | update.PCode = (byte)PCode.Avatar; |
5387 | update.ProfileCurve = 1; | 5793 | update.ProfileCurve = 1; |
5388 | update.PSBlock = Utils.EmptyBytes; | 5794 | update.PSBlock = Utils.EmptyBytes; |
5389 | update.Scale = new Vector3(0.45f, 0.6f, 1.9f); | 5795 | update.Scale = data.Appearance.AvatarSize; |
5796 | // update.Scale.Z -= 0.2f; | ||
5797 | |||
5390 | update.Text = Utils.EmptyBytes; | 5798 | update.Text = Utils.EmptyBytes; |
5391 | update.TextColor = new byte[4]; | 5799 | update.TextColor = new byte[4]; |
5392 | 5800 | ||
@@ -5397,46 +5805,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5397 | update.TextureEntry = Utils.EmptyBytes; | 5805 | update.TextureEntry = Utils.EmptyBytes; |
5398 | // update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; | 5806 | // update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; |
5399 | 5807 | ||
5808 | /* all this flags seem related to prims and not avatars. This allow for wrong viewer side move of a avatar in prim edition mode (anv mantis 854) | ||
5400 | update.UpdateFlags = (uint)( | 5809 | update.UpdateFlags = (uint)( |
5401 | PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | | 5810 | PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | |
5402 | PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | | 5811 | PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | |
5403 | PrimFlags.ObjectOwnerModify); | 5812 | PrimFlags.ObjectOwnerModify); |
5813 | */ | ||
5814 | update.UpdateFlags = 0; | ||
5404 | 5815 | ||
5405 | return update; | 5816 | return update; |
5406 | } | 5817 | } |
5407 | 5818 | ||
5408 | protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID) | 5819 | // protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID) |
5820 | protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart part, ScenePresence sp) | ||
5409 | { | 5821 | { |
5410 | byte[] objectData = new byte[60]; | 5822 | byte[] objectData = new byte[60]; |
5411 | data.RelativePosition.ToBytes(objectData, 0); | 5823 | part.RelativePosition.ToBytes(objectData, 0); |
5412 | data.Velocity.ToBytes(objectData, 12); | 5824 | part.Velocity.ToBytes(objectData, 12); |
5413 | data.Acceleration.ToBytes(objectData, 24); | 5825 | part.Acceleration.ToBytes(objectData, 24); |
5414 | try | 5826 | |
5415 | { | 5827 | Quaternion rotation = part.RotationOffset; |
5416 | data.RotationOffset.ToBytes(objectData, 36); | 5828 | rotation.Normalize(); |
5417 | } | 5829 | rotation.ToBytes(objectData, 36); |
5418 | catch (Exception e) | 5830 | part.AngularVelocity.ToBytes(objectData, 48); |
5419 | { | ||
5420 | m_log.Warn("[LLClientView]: exception converting quaternion to bytes, using Quaternion.Identity. Exception: " + e.ToString()); | ||
5421 | OpenMetaverse.Quaternion.Identity.ToBytes(objectData, 36); | ||
5422 | } | ||
5423 | data.AngularVelocity.ToBytes(objectData, 48); | ||
5424 | 5831 | ||
5425 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | 5832 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); |
5426 | update.ClickAction = (byte)data.ClickAction; | 5833 | update.ClickAction = (byte)part.ClickAction; |
5427 | update.CRC = 0; | 5834 | update.CRC = 0; |
5428 | update.ExtraParams = data.Shape.ExtraParams ?? Utils.EmptyBytes; | 5835 | update.ExtraParams = part.Shape.ExtraParams ?? Utils.EmptyBytes; |
5429 | update.FullID = data.UUID; | 5836 | update.FullID = part.UUID; |
5430 | update.ID = data.LocalId; | 5837 | update.ID = part.LocalId; |
5431 | //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated | 5838 | //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated |
5432 | //update.JointPivot = Vector3.Zero; | 5839 | //update.JointPivot = Vector3.Zero; |
5433 | //update.JointType = 0; | 5840 | //update.JointType = 0; |
5434 | update.Material = data.Material; | 5841 | update.Material = part.Material; |
5435 | update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim | 5842 | /* |
5436 | |||
5437 | if (data.ParentGroup.IsAttachment) | 5843 | if (data.ParentGroup.IsAttachment) |
5438 | { | 5844 | { |
5439 | update.NameValue | 5845 | update.NameValue |
5440 | = Util.StringToBytes256( | 5846 | = Util.StringToBytes256( |
5441 | string.Format("AttachItemID STRING RW SV {0}", data.ParentGroup.FromItemID)); | 5847 | string.Format("AttachItemID STRING RW SV {0}", data.ParentGroup.FromItemID)); |
5442 | 5848 | ||
@@ -5458,50 +5864,91 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5458 | // case for attachments may contain conflicting values that can end up crashing the viewer. | 5864 | // case for attachments may contain conflicting values that can end up crashing the viewer. |
5459 | update.State = data.ParentGroup.RootPart.Shape.State; | 5865 | update.State = data.ParentGroup.RootPart.Shape.State; |
5460 | } | 5866 | } |
5867 | */ | ||
5868 | |||
5869 | if (part.ParentGroup.IsAttachment) | ||
5870 | { | ||
5871 | if (part.IsRoot) | ||
5872 | { | ||
5873 | update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + part.ParentGroup.FromItemID); | ||
5874 | } | ||
5875 | else | ||
5876 | update.NameValue = Utils.EmptyBytes; | ||
5877 | |||
5878 | int st = (int)part.ParentGroup.AttachmentPoint; | ||
5879 | update.State = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ; | ||
5880 | } | ||
5881 | else | ||
5882 | { | ||
5883 | update.NameValue = Utils.EmptyBytes; | ||
5884 | update.State = part.Shape.State; // not sure about this | ||
5885 | } | ||
5461 | 5886 | ||
5462 | update.ObjectData = objectData; | 5887 | update.ObjectData = objectData; |
5463 | update.ParentID = data.ParentID; | 5888 | update.ParentID = part.ParentID; |
5464 | update.PathBegin = data.Shape.PathBegin; | 5889 | update.PathBegin = part.Shape.PathBegin; |
5465 | update.PathCurve = data.Shape.PathCurve; | 5890 | update.PathCurve = part.Shape.PathCurve; |
5466 | update.PathEnd = data.Shape.PathEnd; | 5891 | update.PathEnd = part.Shape.PathEnd; |
5467 | update.PathRadiusOffset = data.Shape.PathRadiusOffset; | 5892 | update.PathRadiusOffset = part.Shape.PathRadiusOffset; |
5468 | update.PathRevolutions = data.Shape.PathRevolutions; | 5893 | update.PathRevolutions = part.Shape.PathRevolutions; |
5469 | update.PathScaleX = data.Shape.PathScaleX; | 5894 | update.PathScaleX = part.Shape.PathScaleX; |
5470 | update.PathScaleY = data.Shape.PathScaleY; | 5895 | update.PathScaleY = part.Shape.PathScaleY; |
5471 | update.PathShearX = data.Shape.PathShearX; | 5896 | update.PathShearX = part.Shape.PathShearX; |
5472 | update.PathShearY = data.Shape.PathShearY; | 5897 | update.PathShearY = part.Shape.PathShearY; |
5473 | update.PathSkew = data.Shape.PathSkew; | 5898 | update.PathSkew = part.Shape.PathSkew; |
5474 | update.PathTaperX = data.Shape.PathTaperX; | 5899 | update.PathTaperX = part.Shape.PathTaperX; |
5475 | update.PathTaperY = data.Shape.PathTaperY; | 5900 | update.PathTaperY = part.Shape.PathTaperY; |
5476 | update.PathTwist = data.Shape.PathTwist; | 5901 | update.PathTwist = part.Shape.PathTwist; |
5477 | update.PathTwistBegin = data.Shape.PathTwistBegin; | 5902 | update.PathTwistBegin = part.Shape.PathTwistBegin; |
5478 | update.PCode = data.Shape.PCode; | 5903 | update.PCode = part.Shape.PCode; |
5479 | update.ProfileBegin = data.Shape.ProfileBegin; | 5904 | update.ProfileBegin = part.Shape.ProfileBegin; |
5480 | update.ProfileCurve = data.Shape.ProfileCurve; | 5905 | update.ProfileCurve = part.Shape.ProfileCurve; |
5481 | update.ProfileEnd = data.Shape.ProfileEnd; | 5906 | |
5482 | update.ProfileHollow = data.Shape.ProfileHollow; | 5907 | ushort profileBegin = part.Shape.ProfileBegin; |
5483 | update.PSBlock = data.ParticleSystem ?? Utils.EmptyBytes; | 5908 | ushort profileHollow = part.Shape.ProfileHollow; |
5484 | update.TextColor = data.GetTextColor().GetBytes(false); | 5909 | |
5485 | update.TextureAnim = data.TextureAnimation ?? Utils.EmptyBytes; | 5910 | if(part.Shape.SculptType == (byte)SculptType.Mesh) // filter out hack |
5486 | update.TextureEntry = data.Shape.TextureEntry ?? Utils.EmptyBytes; | 5911 | { |
5487 | update.Scale = data.Shape.Scale; | 5912 | update.ProfileCurve = (byte)(part.Shape.ProfileCurve & 0x0f); |
5488 | update.Text = Util.StringToBytes256(data.Text); | 5913 | // fix old values that confused viewers |
5489 | update.MediaURL = Util.StringToBytes256(data.MediaUrl); | 5914 | if(profileBegin == 1) |
5915 | profileBegin = 9375; | ||
5916 | if(profileHollow == 1) | ||
5917 | profileHollow = 27500; | ||
5918 | // fix torus hole size Y that also confuse some viewers | ||
5919 | if(update.ProfileCurve == (byte)ProfileShape.Circle && update.PathScaleY < 150) | ||
5920 | update.PathScaleY = 150; | ||
5921 | } | ||
5922 | else | ||
5923 | { | ||
5924 | update.ProfileCurve = part.Shape.ProfileCurve; | ||
5925 | } | ||
5926 | |||
5927 | update.ProfileHollow = profileHollow; | ||
5928 | update.ProfileBegin = profileBegin; | ||
5929 | update.ProfileEnd = part.Shape.ProfileEnd; | ||
5930 | update.PSBlock = part.ParticleSystem ?? Utils.EmptyBytes; | ||
5931 | update.TextColor = part.GetTextColor().GetBytes(false); | ||
5932 | update.TextureAnim = part.TextureAnimation ?? Utils.EmptyBytes; | ||
5933 | update.TextureEntry = part.Shape.TextureEntry ?? Utils.EmptyBytes; | ||
5934 | update.Scale = part.Shape.Scale; | ||
5935 | update.Text = Util.StringToBytes(part.Text, 255); | ||
5936 | update.MediaURL = Util.StringToBytes(part.MediaUrl, 255); | ||
5490 | 5937 | ||
5491 | #region PrimFlags | 5938 | #region PrimFlags |
5492 | 5939 | ||
5493 | PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(recipientID, data.UUID); | 5940 | PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(part, sp); |
5494 | 5941 | ||
5495 | // Don't send the CreateSelected flag to everyone | 5942 | // Don't send the CreateSelected flag to everyone |
5496 | flags &= ~PrimFlags.CreateSelected; | 5943 | flags &= ~PrimFlags.CreateSelected; |
5497 | 5944 | ||
5498 | if (recipientID == data.OwnerID) | 5945 | if (sp.UUID == part.OwnerID) |
5499 | { | 5946 | { |
5500 | if (data.CreateSelected) | 5947 | if (part.CreateSelected) |
5501 | { | 5948 | { |
5502 | // Only send this flag once, then unset it | 5949 | // Only send this flag once, then unset it |
5503 | flags |= PrimFlags.CreateSelected; | 5950 | flags |= PrimFlags.CreateSelected; |
5504 | data.CreateSelected = false; | 5951 | part.CreateSelected = false; |
5505 | } | 5952 | } |
5506 | } | 5953 | } |
5507 | 5954 | ||
@@ -5513,21 +5960,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5513 | 5960 | ||
5514 | #endregion PrimFlags | 5961 | #endregion PrimFlags |
5515 | 5962 | ||
5516 | if (data.Sound != UUID.Zero) | 5963 | if (part.Sound != UUID.Zero) |
5517 | { | 5964 | { |
5518 | update.Sound = data.Sound; | 5965 | update.Sound = part.Sound; |
5519 | update.OwnerID = data.OwnerID; | 5966 | update.OwnerID = part.OwnerID; |
5520 | update.Gain = (float)data.SoundGain; | 5967 | update.Gain = (float)part.SoundGain; |
5521 | update.Radius = (float)data.SoundRadius; | 5968 | update.Radius = (float)part.SoundRadius; |
5522 | update.Flags = data.SoundFlags; | 5969 | update.Flags = part.SoundFlags; |
5523 | } | 5970 | } |
5524 | 5971 | ||
5525 | switch ((PCode)data.Shape.PCode) | 5972 | switch ((PCode)part.Shape.PCode) |
5526 | { | 5973 | { |
5527 | case PCode.Grass: | 5974 | case PCode.Grass: |
5528 | case PCode.Tree: | 5975 | case PCode.Tree: |
5529 | case PCode.NewTree: | 5976 | case PCode.NewTree: |
5530 | update.Data = new byte[] { data.Shape.State }; | 5977 | update.Data = new byte[] { part.Shape.State }; |
5531 | break; | 5978 | break; |
5532 | default: | 5979 | default: |
5533 | update.Data = Utils.EmptyBytes; | 5980 | update.Data = Utils.EmptyBytes; |
@@ -5556,14 +6003,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5556 | OutPacket(packet, ThrottleOutPacketType.Task); | 6003 | OutPacket(packet, ThrottleOutPacketType.Task); |
5557 | } | 6004 | } |
5558 | 6005 | ||
5559 | public ulong GetGroupPowers(UUID groupID) | 6006 | public Dictionary<UUID, ulong> GetGroupPowers() |
5560 | { | 6007 | { |
5561 | if (groupID == ActiveGroupId) | 6008 | lock(m_groupPowers) |
5562 | return ActiveGroupPowers; | 6009 | { |
6010 | return new Dictionary<UUID, ulong>(m_groupPowers); | ||
6011 | } | ||
6012 | } | ||
5563 | 6013 | ||
5564 | if (m_groupPowers.ContainsKey(groupID)) | 6014 | public void SetGroupPowers(Dictionary<UUID, ulong> powers) |
5565 | return m_groupPowers[groupID]; | 6015 | { |
6016 | lock(m_groupPowers) | ||
6017 | { | ||
6018 | m_groupPowers.Clear(); | ||
6019 | m_groupPowers = powers; | ||
6020 | } | ||
6021 | } | ||
5566 | 6022 | ||
6023 | public ulong GetGroupPowers(UUID groupID) | ||
6024 | { | ||
6025 | lock(m_groupPowers) | ||
6026 | { | ||
6027 | if (m_groupPowers.ContainsKey(groupID)) | ||
6028 | return m_groupPowers[groupID]; | ||
6029 | } | ||
5567 | return 0; | 6030 | return 0; |
5568 | } | 6031 | } |
5569 | 6032 | ||
@@ -5579,18 +6042,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5579 | // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs | 6042 | // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs |
5580 | // for each AgentUpdate packet. | 6043 | // for each AgentUpdate packet. |
5581 | AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); | 6044 | AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); |
5582 | 6045 | ||
5583 | AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); | 6046 | AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); |
6047 | AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false); | ||
6048 | AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false); | ||
5584 | AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); | 6049 | AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); |
5585 | AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); | 6050 | AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); |
5586 | AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); | 6051 | AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); |
5587 | AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false); | 6052 | AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false); |
5588 | AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest); | 6053 | AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest); |
5589 | AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest); | 6054 | AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest); |
5590 | AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage, true, true); | 6055 | AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage); |
5591 | AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest, true, true); | 6056 | AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest); |
5592 | AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer); | 6057 | AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer); |
5593 | AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate, true, true); | 6058 | AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate); |
5594 | AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply); | 6059 | AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply); |
5595 | AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage); | 6060 | AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage); |
5596 | AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship); | 6061 | AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship); |
@@ -5598,6 +6063,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5598 | AddLocalPacketHandler(PacketType.TerminateFriendship, HandlerTerminateFriendship); | 6063 | AddLocalPacketHandler(PacketType.TerminateFriendship, HandlerTerminateFriendship); |
5599 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); | 6064 | AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); |
5600 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); | 6065 | AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); |
6066 | AddLocalPacketHandler(PacketType.RezRestoreToWorld, HandlerRezRestoreToWorld); | ||
5601 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); | 6067 | AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); |
5602 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false); | 6068 | AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false); |
5603 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); | 6069 | AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); |
@@ -5732,6 +6198,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5732 | AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); | 6198 | AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); |
5733 | AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); | 6199 | AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); |
5734 | AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); | 6200 | AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); |
6201 | AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments); | ||
5735 | AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); | 6202 | AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); |
5736 | AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); | 6203 | AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); |
5737 | AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); | 6204 | AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); |
@@ -5775,8 +6242,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5775 | AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete); | 6242 | AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete); |
5776 | AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete); | 6243 | AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete); |
5777 | AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate); | 6244 | AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate); |
5778 | AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate, true, true); | 6245 | AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate); |
5779 | AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate, true, true); | 6246 | AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate); |
5780 | AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights); | 6247 | AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights); |
5781 | AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery); | 6248 | AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery); |
5782 | AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry); | 6249 | AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry); |
@@ -5798,7 +6265,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5798 | AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); | 6265 | AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); |
5799 | AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); | 6266 | AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); |
5800 | AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); | 6267 | AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); |
5801 | 6268 | AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags); | |
6269 | AddLocalPacketHandler(PacketType.RevokePermissions, HandleRevokePermissions); | ||
5802 | AddGenericPacketHandler("autopilot", HandleAutopilot); | 6270 | AddGenericPacketHandler("autopilot", HandleAutopilot); |
5803 | } | 6271 | } |
5804 | 6272 | ||
@@ -5809,7 +6277,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5809 | #region Scene/Avatar | 6277 | #region Scene/Avatar |
5810 | 6278 | ||
5811 | // Threshold for body rotation to be a significant agent update | 6279 | // Threshold for body rotation to be a significant agent update |
5812 | private const float QDELTA = 0.000001f; | 6280 | // use the abs of cos |
6281 | private const float QDELTABody = 1.0f - 0.00005f; | ||
6282 | private const float QDELTAHead = 1.0f - 0.00005f; | ||
5813 | // Threshold for camera rotation to be a significant agent update | 6283 | // Threshold for camera rotation to be a significant agent update |
5814 | private const float VDELTA = 0.01f; | 6284 | private const float VDELTA = 0.01f; |
5815 | 6285 | ||
@@ -5832,27 +6302,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5832 | /// <param name='x'></param> | 6302 | /// <param name='x'></param> |
5833 | private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) | 6303 | private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) |
5834 | { | 6304 | { |
5835 | float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); | 6305 | if( |
5836 | //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); | 6306 | (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed |
5837 | 6307 | // || ((x.ControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0 && | |
5838 | bool movementSignificant = | 6308 | // (x.ControlFlags & 0x3f8dfff) != 0) // we need to rotate the av on fly |
5839 | (qdelta1 > QDELTA) // significant if body rotation above threshold | 6309 | || x.ControlFlags != (byte)AgentManager.ControlFlags.NONE// actually all movement controls need to pass |
5840 | // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack | ||
5841 | // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold | ||
5842 | || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed | ||
5843 | || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands | ||
5844 | || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed | ||
5845 | || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed | 6310 | || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed |
5846 | || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed | 6311 | || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed |
5847 | ; | 6312 | || (Math.Abs(x.Far - m_thisAgentUpdateArgs.Far) >= 32) // significant if far distance changed |
5848 | //if (movementSignificant) | 6313 | ) |
5849 | //{ | 6314 | return true; |
5850 | //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", | 6315 | |
5851 | // qdelta1, qdelta2); | 6316 | float qdelta1 = Math.Abs(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation)); |
5852 | //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", | 6317 | //qdelta2 = Math.Abs(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation)); |
5853 | // x.ControlFlags, x.Flags, x.Far, x.State); | 6318 | |
5854 | //} | 6319 | if( |
5855 | return movementSignificant; | 6320 | qdelta1 < QDELTABody // significant if body rotation above(below cos) threshold |
6321 | // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack | ||
6322 | // || qdelta2 < QDELTAHead // significant if head rotation above(below cos) threshold | ||
6323 | ) | ||
6324 | return true; | ||
6325 | |||
6326 | return false; | ||
5856 | } | 6327 | } |
5857 | 6328 | ||
5858 | /// <summary> | 6329 | /// <summary> |
@@ -5863,78 +6334,95 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5863 | /// <param name='x'></param> | 6334 | /// <param name='x'></param> |
5864 | private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) | 6335 | private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) |
5865 | { | 6336 | { |
5866 | float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); | 6337 | if(Math.Abs(x.CameraCenter.X - m_thisAgentUpdateArgs.CameraCenter.X) > VDELTA || |
5867 | float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); | 6338 | Math.Abs(x.CameraCenter.Y - m_thisAgentUpdateArgs.CameraCenter.Y) > VDELTA || |
5868 | float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); | 6339 | Math.Abs(x.CameraCenter.Z - m_thisAgentUpdateArgs.CameraCenter.Z) > VDELTA || |
5869 | float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); | ||
5870 | 6340 | ||
5871 | bool cameraSignificant = | 6341 | Math.Abs(x.CameraAtAxis.X - m_thisAgentUpdateArgs.CameraAtAxis.X) > VDELTA || |
5872 | (vdelta1 > VDELTA) || | 6342 | Math.Abs(x.CameraAtAxis.Y - m_thisAgentUpdateArgs.CameraAtAxis.Y) > VDELTA || |
5873 | (vdelta2 > VDELTA) || | 6343 | // Math.Abs(x.CameraAtAxis.Z - m_thisAgentUpdateArgs.CameraAtAxis.Z) > VDELTA || |
5874 | (vdelta3 > VDELTA) || | ||
5875 | (vdelta4 > VDELTA) | ||
5876 | ; | ||
5877 | 6344 | ||
5878 | //if (cameraSignificant) | 6345 | Math.Abs(x.CameraLeftAxis.X - m_thisAgentUpdateArgs.CameraLeftAxis.X) > VDELTA || |
5879 | //{ | 6346 | Math.Abs(x.CameraLeftAxis.Y - m_thisAgentUpdateArgs.CameraLeftAxis.Y) > VDELTA || |
5880 | //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", | 6347 | // Math.Abs(x.CameraLeftAxis.Z - m_thisAgentUpdateArgs.CameraLeftAxis.Z) > VDELTA || |
5881 | // x.CameraAtAxis, x.CameraCenter); | ||
5882 | //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", | ||
5883 | // x.CameraLeftAxis, x.CameraUpAxis); | ||
5884 | //} | ||
5885 | 6348 | ||
5886 | return cameraSignificant; | 6349 | Math.Abs(x.CameraUpAxis.X - m_thisAgentUpdateArgs.CameraUpAxis.X) > VDELTA || |
5887 | } | 6350 | Math.Abs(x.CameraUpAxis.Y - m_thisAgentUpdateArgs.CameraUpAxis.Y) > VDELTA |
6351 | // Math.Abs(x.CameraLeftAxis.Z - m_thisAgentUpdateArgs.CameraLeftAxis.Z) > VDELTA || | ||
6352 | ) | ||
6353 | return true; | ||
5888 | 6354 | ||
5889 | private bool HandleAgentUpdate(IClientAPI sener, Packet packet) | 6355 | return false; |
5890 | { | 6356 | } |
5891 | // We got here, which means that something in agent update was significant | ||
5892 | 6357 | ||
6358 | private bool HandleAgentUpdate(IClientAPI sender, Packet packet) | ||
6359 | { | ||
5893 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | 6360 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; |
5894 | AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; | 6361 | AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; |
5895 | 6362 | ||
5896 | if (x.AgentID != AgentId || x.SessionID != SessionId) | 6363 | if (x.AgentID != AgentId || x.SessionID != SessionId) |
6364 | { | ||
6365 | PacketPool.Instance.ReturnPacket(packet); | ||
5897 | return false; | 6366 | return false; |
6367 | } | ||
6368 | |||
6369 | uint seq = packet.Header.Sequence; | ||
6370 | |||
6371 | TotalAgentUpdates++; | ||
6372 | // dont let ignored updates pollute this throttles | ||
6373 | if(SceneAgent == null || SceneAgent.IsChildAgent || | ||
6374 | SceneAgent.IsInTransit || seq <= m_thisAgentUpdateArgs.lastpacketSequence ) | ||
6375 | { | ||
6376 | // throttle reset is done at MoveAgentIntoRegion() | ||
6377 | // called by scenepresence on completemovement | ||
6378 | PacketPool.Instance.ReturnPacket(packet); | ||
6379 | return true; | ||
6380 | } | ||
6381 | |||
6382 | m_thisAgentUpdateArgs.lastpacketSequence = seq; | ||
5898 | 6383 | ||
5899 | // Before we update the current m_thisAgentUpdateArgs, let's check this again | ||
5900 | // to see what exactly changed | ||
5901 | bool movement = CheckAgentMovementUpdateSignificance(x); | 6384 | bool movement = CheckAgentMovementUpdateSignificance(x); |
5902 | bool camera = CheckAgentCameraUpdateSignificance(x); | 6385 | bool camera = CheckAgentCameraUpdateSignificance(x); |
5903 | 6386 | ||
5904 | m_thisAgentUpdateArgs.AgentID = x.AgentID; | ||
5905 | m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; | ||
5906 | m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; | ||
5907 | m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; | ||
5908 | m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; | ||
5909 | m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; | ||
5910 | m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; | ||
5911 | m_thisAgentUpdateArgs.Far = x.Far; | ||
5912 | m_thisAgentUpdateArgs.Flags = x.Flags; | ||
5913 | m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; | ||
5914 | m_thisAgentUpdateArgs.SessionID = x.SessionID; | ||
5915 | m_thisAgentUpdateArgs.State = x.State; | ||
5916 | |||
5917 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; | ||
5918 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; | ||
5919 | UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate; | ||
5920 | |||
5921 | // Was there a significant movement/state change? | 6387 | // Was there a significant movement/state change? |
5922 | if (movement) | 6388 | if (movement) |
5923 | { | 6389 | { |
6390 | m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; | ||
6391 | m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; | ||
6392 | m_thisAgentUpdateArgs.Far = x.Far; | ||
6393 | m_thisAgentUpdateArgs.Flags = x.Flags; | ||
6394 | m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; | ||
6395 | m_thisAgentUpdateArgs.State = x.State; | ||
6396 | |||
6397 | m_thisAgentUpdateArgs.NeedsCameraCollision = !camera; | ||
6398 | |||
6399 | UpdateAgent handlerAgentUpdate = OnAgentUpdate; | ||
6400 | UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; | ||
6401 | |||
5924 | if (handlerPreAgentUpdate != null) | 6402 | if (handlerPreAgentUpdate != null) |
5925 | OnPreAgentUpdate(this, m_thisAgentUpdateArgs); | 6403 | OnPreAgentUpdate(this, m_thisAgentUpdateArgs); |
5926 | 6404 | ||
5927 | if (handlerAgentUpdate != null) | 6405 | if (handlerAgentUpdate != null) |
5928 | OnAgentUpdate(this, m_thisAgentUpdateArgs); | 6406 | OnAgentUpdate(this, m_thisAgentUpdateArgs); |
6407 | |||
5929 | } | 6408 | } |
6409 | |||
5930 | // Was there a significant camera(s) change? | 6410 | // Was there a significant camera(s) change? |
5931 | if (camera) | 6411 | if (camera) |
6412 | { | ||
6413 | m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; | ||
6414 | m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; | ||
6415 | m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; | ||
6416 | m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; | ||
6417 | |||
6418 | m_thisAgentUpdateArgs.NeedsCameraCollision = true; | ||
6419 | |||
6420 | UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate; | ||
6421 | |||
5932 | if (handlerAgentCameraUpdate != null) | 6422 | if (handlerAgentCameraUpdate != null) |
5933 | handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs); | 6423 | handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs); |
5934 | 6424 | ||
5935 | handlerAgentUpdate = null; | 6425 | } |
5936 | handlerPreAgentUpdate = null; | ||
5937 | handlerAgentCameraUpdate = null; | ||
5938 | 6426 | ||
5939 | PacketPool.Instance.ReturnPacket(packet); | 6427 | PacketPool.Instance.ReturnPacket(packet); |
5940 | 6428 | ||
@@ -5967,6 +6455,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5967 | ParcelGodMarkAsContentPacket ParcelGodMarkAsContent = | 6455 | ParcelGodMarkAsContentPacket ParcelGodMarkAsContent = |
5968 | (ParcelGodMarkAsContentPacket)Packet; | 6456 | (ParcelGodMarkAsContentPacket)Packet; |
5969 | 6457 | ||
6458 | if(SessionId != ParcelGodMarkAsContent.AgentData.SessionID || AgentId != ParcelGodMarkAsContent.AgentData.AgentID) | ||
6459 | return false; | ||
6460 | |||
5970 | ParcelGodMark ParcelGodMarkAsContentHandler = OnParcelGodMark; | 6461 | ParcelGodMark ParcelGodMarkAsContentHandler = OnParcelGodMark; |
5971 | if (ParcelGodMarkAsContentHandler != null) | 6462 | if (ParcelGodMarkAsContentHandler != null) |
5972 | { | 6463 | { |
@@ -5982,6 +6473,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5982 | { | 6473 | { |
5983 | FreezeUserPacket FreezeUser = (FreezeUserPacket)Packet; | 6474 | FreezeUserPacket FreezeUser = (FreezeUserPacket)Packet; |
5984 | 6475 | ||
6476 | if(SessionId != FreezeUser.AgentData.SessionID || AgentId != FreezeUser.AgentData.AgentID) | ||
6477 | return false; | ||
6478 | |||
5985 | FreezeUserUpdate FreezeUserHandler = OnParcelFreezeUser; | 6479 | FreezeUserUpdate FreezeUserHandler = OnParcelFreezeUser; |
5986 | if (FreezeUserHandler != null) | 6480 | if (FreezeUserHandler != null) |
5987 | { | 6481 | { |
@@ -5999,6 +6493,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5999 | EjectUserPacket EjectUser = | 6493 | EjectUserPacket EjectUser = |
6000 | (EjectUserPacket)Packet; | 6494 | (EjectUserPacket)Packet; |
6001 | 6495 | ||
6496 | if(SessionId != EjectUser.AgentData.SessionID || AgentId != EjectUser.AgentData.AgentID) | ||
6497 | return false; | ||
6498 | |||
6002 | EjectUserUpdate EjectUserHandler = OnParcelEjectUser; | 6499 | EjectUserUpdate EjectUserHandler = OnParcelEjectUser; |
6003 | if (EjectUserHandler != null) | 6500 | if (EjectUserHandler != null) |
6004 | { | 6501 | { |
@@ -6016,6 +6513,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6016 | ParcelBuyPassPacket ParcelBuyPass = | 6513 | ParcelBuyPassPacket ParcelBuyPass = |
6017 | (ParcelBuyPassPacket)Packet; | 6514 | (ParcelBuyPassPacket)Packet; |
6018 | 6515 | ||
6516 | if(SessionId != ParcelBuyPass.AgentData.SessionID || AgentId != ParcelBuyPass.AgentData.AgentID) | ||
6517 | return false; | ||
6518 | |||
6019 | ParcelBuyPass ParcelBuyPassHandler = OnParcelBuyPass; | 6519 | ParcelBuyPass ParcelBuyPassHandler = OnParcelBuyPass; |
6020 | if (ParcelBuyPassHandler != null) | 6520 | if (ParcelBuyPassHandler != null) |
6021 | { | 6521 | { |
@@ -6048,8 +6548,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6048 | 6548 | ||
6049 | private bool HandleUUIDGroupNameRequest(IClientAPI sender, Packet Pack) | 6549 | private bool HandleUUIDGroupNameRequest(IClientAPI sender, Packet Pack) |
6050 | { | 6550 | { |
6051 | UUIDGroupNameRequestPacket upack = (UUIDGroupNameRequestPacket)Pack; | 6551 | ScenePresence sp = (ScenePresence)SceneAgent; |
6552 | if(sp == null || sp.IsDeleted || (sp.IsInTransit && !sp.IsInLocalTransit)) | ||
6553 | return true; | ||
6052 | 6554 | ||
6555 | UUIDGroupNameRequestPacket upack = (UUIDGroupNameRequestPacket)Pack; | ||
6053 | 6556 | ||
6054 | for (int i = 0; i < upack.UUIDNameBlock.Length; i++) | 6557 | for (int i = 0; i < upack.UUIDNameBlock.Length; i++) |
6055 | { | 6558 | { |
@@ -6101,7 +6604,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6101 | } | 6604 | } |
6102 | } | 6605 | } |
6103 | } | 6606 | } |
6104 | 6607 | ||
6105 | //m_log.Debug("[LLCLIENTVIEW]: Not handling GenericMessage with method-type of: " + method); | 6608 | //m_log.Debug("[LLCLIENTVIEW]: Not handling GenericMessage with method-type of: " + method); |
6106 | return false; | 6609 | return false; |
6107 | } | 6610 | } |
@@ -6150,6 +6653,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6150 | return true; | 6653 | return true; |
6151 | } | 6654 | } |
6152 | 6655 | ||
6656 | private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack) | ||
6657 | { | ||
6658 | VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack; | ||
6659 | if (p.AgentData.SessionID != SessionId || | ||
6660 | p.AgentData.AgentID != AgentId) | ||
6661 | return true; | ||
6662 | |||
6663 | // m_VelocityInterpolate = false; | ||
6664 | return true; | ||
6665 | } | ||
6666 | |||
6667 | private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack) | ||
6668 | { | ||
6669 | VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack; | ||
6670 | if (p.AgentData.SessionID != SessionId || | ||
6671 | p.AgentData.AgentID != AgentId) | ||
6672 | return true; | ||
6673 | |||
6674 | // m_VelocityInterpolate = true; | ||
6675 | return true; | ||
6676 | } | ||
6677 | |||
6678 | |||
6153 | private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) | 6679 | private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) |
6154 | { | 6680 | { |
6155 | AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; | 6681 | AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; |
@@ -6442,11 +6968,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6442 | RezObject handlerRezObject = OnRezObject; | 6968 | RezObject handlerRezObject = OnRezObject; |
6443 | if (handlerRezObject != null) | 6969 | if (handlerRezObject != null) |
6444 | { | 6970 | { |
6445 | handlerRezObject(this, rezPacket.InventoryData.ItemID, rezPacket.RezData.RayEnd, | 6971 | UUID rezGroupID = rezPacket.AgentData.GroupID; |
6446 | rezPacket.RezData.RayStart, rezPacket.RezData.RayTargetID, | 6972 | if(!IsGroupMember(rezGroupID)) |
6447 | rezPacket.RezData.BypassRaycast, rezPacket.RezData.RayEndIsIntersection, | 6973 | rezGroupID = UUID.Zero; |
6448 | rezPacket.RezData.RezSelected, rezPacket.RezData.RemoveItem, | 6974 | handlerRezObject(this, rezPacket.InventoryData.ItemID, rezGroupID, rezPacket.RezData.RayEnd, |
6449 | rezPacket.RezData.FromTaskID); | 6975 | rezPacket.RezData.RayStart, rezPacket.RezData.RayTargetID, |
6976 | rezPacket.RezData.BypassRaycast, rezPacket.RezData.RayEndIsIntersection, | ||
6977 | rezPacket.RezData.RezSelected, rezPacket.RezData.RemoveItem, | ||
6978 | rezPacket.RezData.FromTaskID); | ||
6450 | } | 6979 | } |
6451 | return true; | 6980 | return true; |
6452 | } | 6981 | } |
@@ -6485,6 +7014,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6485 | return true; | 7014 | return true; |
6486 | } | 7015 | } |
6487 | 7016 | ||
7017 | private bool HandlerRezRestoreToWorld(IClientAPI sender, Packet Pack) | ||
7018 | { | ||
7019 | RezRestoreToWorldPacket restore = (RezRestoreToWorldPacket)Pack; | ||
7020 | |||
7021 | #region Packet Session and User Check | ||
7022 | if (m_checkPackets) | ||
7023 | { | ||
7024 | if (restore.AgentData.SessionID != SessionId || | ||
7025 | restore.AgentData.AgentID != AgentId) | ||
7026 | return true; | ||
7027 | } | ||
7028 | #endregion | ||
7029 | |||
7030 | RezRestoreToWorld handlerRezRestoreToWorld = OnRezRestoreToWorld; | ||
7031 | if (handlerRezRestoreToWorld != null) | ||
7032 | handlerRezRestoreToWorld(this, restore.InventoryData.ItemID); | ||
7033 | |||
7034 | return true; | ||
7035 | } | ||
7036 | |||
6488 | private bool HandlerModifyLand(IClientAPI sender, Packet Pack) | 7037 | private bool HandlerModifyLand(IClientAPI sender, Packet Pack) |
6489 | { | 7038 | { |
6490 | ModifyLandPacket modify = (ModifyLandPacket)Pack; | 7039 | ModifyLandPacket modify = (ModifyLandPacket)Pack; |
@@ -6501,9 +7050,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6501 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); | 7050 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); |
6502 | if (modify.ParcelData.Length > 0) | 7051 | if (modify.ParcelData.Length > 0) |
6503 | { | 7052 | { |
6504 | // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore, | 7053 | // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore, |
6505 | // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit. | 7054 | // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit. |
6506 | m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable | ||
6507 | if (OnModifyTerrain != null) | 7055 | if (OnModifyTerrain != null) |
6508 | { | 7056 | { |
6509 | for (int i = 0; i < modify.ParcelData.Length; i++) | 7057 | for (int i = 0; i < modify.ParcelData.Length; i++) |
@@ -6519,7 +7067,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6519 | } | 7067 | } |
6520 | } | 7068 | } |
6521 | } | 7069 | } |
6522 | m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again | ||
6523 | } | 7070 | } |
6524 | 7071 | ||
6525 | return true; | 7072 | return true; |
@@ -6580,7 +7127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6580 | byte[] visualparams = new byte[appear.VisualParam.Length]; | 7127 | byte[] visualparams = new byte[appear.VisualParam.Length]; |
6581 | for (int i = 0; i < appear.VisualParam.Length; i++) | 7128 | for (int i = 0; i < appear.VisualParam.Length; i++) |
6582 | visualparams[i] = appear.VisualParam[i].ParamValue; | 7129 | visualparams[i] = appear.VisualParam[i].ParamValue; |
6583 | //var b = appear.WearableData[0]; | 7130 | //var b = appear.WearableData[0]; |
6584 | 7131 | ||
6585 | Primitive.TextureEntry te = null; | 7132 | Primitive.TextureEntry te = null; |
6586 | if (appear.ObjectData.TextureEntry.Length > 1) | 7133 | if (appear.ObjectData.TextureEntry.Length > 1) |
@@ -6588,7 +7135,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6588 | 7135 | ||
6589 | WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; | 7136 | WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; |
6590 | for (int i=0; i<appear.WearableData.Length;i++) | 7137 | for (int i=0; i<appear.WearableData.Length;i++) |
6591 | cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)}; | 7138 | cacheitems[i] = new WearableCacheItem(){ |
7139 | CacheId = appear.WearableData[i].CacheID, | ||
7140 | TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex) | ||
7141 | }; | ||
6592 | 7142 | ||
6593 | 7143 | ||
6594 | 7144 | ||
@@ -6794,13 +7344,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6794 | return true; | 7344 | return true; |
6795 | } | 7345 | } |
6796 | 7346 | ||
6797 | private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) | 7347 | private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) |
6798 | { | 7348 | { |
7349 | m_log.DebugFormat("[LLClientView] HandleCompleteAgentMovement"); | ||
7350 | |||
6799 | Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; | 7351 | Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; |
6800 | if (handlerCompleteMovementToRegion != null) | 7352 | if (handlerCompleteMovementToRegion != null) |
6801 | { | 7353 | { |
6802 | handlerCompleteMovementToRegion(sender, true); | 7354 | handlerCompleteMovementToRegion(sender, true); |
6803 | } | 7355 | } |
7356 | else | ||
7357 | m_log.Debug("HandleCompleteAgentMovement NULL handler"); | ||
7358 | |||
6804 | handlerCompleteMovementToRegion = null; | 7359 | handlerCompleteMovementToRegion = null; |
6805 | 7360 | ||
6806 | return true; | 7361 | return true; |
@@ -6818,7 +7373,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6818 | return true; | 7373 | return true; |
6819 | } | 7374 | } |
6820 | #endregion | 7375 | #endregion |
6821 | 7376 | /* | |
6822 | StartAnim handlerStartAnim = null; | 7377 | StartAnim handlerStartAnim = null; |
6823 | StopAnim handlerStopAnim = null; | 7378 | StopAnim handlerStopAnim = null; |
6824 | 7379 | ||
@@ -6842,6 +7397,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6842 | } | 7397 | } |
6843 | } | 7398 | } |
6844 | return true; | 7399 | return true; |
7400 | */ | ||
7401 | ChangeAnim handlerChangeAnim = null; | ||
7402 | |||
7403 | for (int i = 0; i < AgentAni.AnimationList.Length; i++) | ||
7404 | { | ||
7405 | handlerChangeAnim = OnChangeAnim; | ||
7406 | if (handlerChangeAnim != null) | ||
7407 | { | ||
7408 | handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false); | ||
7409 | } | ||
7410 | } | ||
7411 | |||
7412 | handlerChangeAnim = OnChangeAnim; | ||
7413 | if (handlerChangeAnim != null) | ||
7414 | { | ||
7415 | handlerChangeAnim(UUID.Zero, false, true); | ||
7416 | } | ||
7417 | |||
7418 | return true; | ||
6845 | } | 7419 | } |
6846 | 7420 | ||
6847 | private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) | 7421 | private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) |
@@ -6997,7 +7571,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6997 | SendUserInfoReply(false, true, ""); | 7571 | SendUserInfoReply(false, true, ""); |
6998 | } | 7572 | } |
6999 | return true; | 7573 | return true; |
7000 | |||
7001 | } | 7574 | } |
7002 | 7575 | ||
7003 | private bool HandleUpdateUserInfo(IClientAPI sender, Packet Pack) | 7576 | private bool HandleUpdateUserInfo(IClientAPI sender, Packet Pack) |
@@ -7087,6 +7660,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7087 | #endregion | 7660 | #endregion |
7088 | 7661 | ||
7089 | m_udpClient.SetThrottles(atpack.Throttle.Throttles); | 7662 | m_udpClient.SetThrottles(atpack.Throttle.Throttles); |
7663 | GenericCall2 handler = OnUpdateThrottles; | ||
7664 | if (handler != null) | ||
7665 | { | ||
7666 | handler(); | ||
7667 | } | ||
7090 | return true; | 7668 | return true; |
7091 | } | 7669 | } |
7092 | 7670 | ||
@@ -7207,7 +7785,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7207 | 7785 | ||
7208 | AddNewPrim handlerAddPrim = OnAddPrim; | 7786 | AddNewPrim handlerAddPrim = OnAddPrim; |
7209 | if (handlerAddPrim != null) | 7787 | if (handlerAddPrim != null) |
7210 | handlerAddPrim(AgentId, ActiveGroupId, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection); | 7788 | handlerAddPrim(AgentId, addPacket.AgentData.GroupID, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection); |
7211 | } | 7789 | } |
7212 | return true; | 7790 | return true; |
7213 | } | 7791 | } |
@@ -7302,14 +7880,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7302 | 7880 | ||
7303 | ObjectDuplicate handlerObjectDuplicate = null; | 7881 | ObjectDuplicate handlerObjectDuplicate = null; |
7304 | 7882 | ||
7305 | for (int i = 0; i < dupe.ObjectData.Length; i++) | 7883 | handlerObjectDuplicate = OnObjectDuplicate; |
7884 | if (handlerObjectDuplicate != null) | ||
7306 | { | 7885 | { |
7307 | handlerObjectDuplicate = OnObjectDuplicate; | 7886 | for (int i = 0; i < dupe.ObjectData.Length; i++) |
7308 | if (handlerObjectDuplicate != null) | ||
7309 | { | 7887 | { |
7888 | UUID rezGroupID = dupe.AgentData.GroupID; | ||
7889 | if(!IsGroupMember(rezGroupID)) | ||
7890 | rezGroupID = UUID.Zero; | ||
7310 | handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset, | 7891 | handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset, |
7311 | dupe.SharedData.DuplicateFlags, AgentId, | 7892 | dupe.SharedData.DuplicateFlags, AgentId, |
7312 | ActiveGroupId); | 7893 | rezGroupID); |
7313 | } | 7894 | } |
7314 | } | 7895 | } |
7315 | 7896 | ||
@@ -7354,16 +7935,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7354 | return true; | 7935 | return true; |
7355 | } | 7936 | } |
7356 | #endregion | 7937 | #endregion |
7357 | 7938 | List<uint> thisSelection = new List<uint>(); | |
7358 | ObjectSelect handlerObjectSelect = null; | 7939 | ObjectSelect handlerObjectSelect = null; |
7359 | 7940 | uint objID; | |
7360 | for (int i = 0; i < incomingselect.ObjectData.Length; i++) | 7941 | handlerObjectSelect = OnObjectSelect; |
7942 | if (handlerObjectSelect != null) | ||
7361 | { | 7943 | { |
7362 | handlerObjectSelect = OnObjectSelect; | 7944 | for (int i = 0; i < incomingselect.ObjectData.Length; i++) |
7363 | if (handlerObjectSelect != null) | ||
7364 | { | 7945 | { |
7365 | handlerObjectSelect(incomingselect.ObjectData[i].ObjectLocalID, this); | 7946 | objID = incomingselect.ObjectData[i].ObjectLocalID; |
7947 | thisSelection.Add(objID); | ||
7366 | } | 7948 | } |
7949 | |||
7950 | handlerObjectSelect(thisSelection, this); | ||
7367 | } | 7951 | } |
7368 | return true; | 7952 | return true; |
7369 | } | 7953 | } |
@@ -7382,13 +7966,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7382 | #endregion | 7966 | #endregion |
7383 | 7967 | ||
7384 | ObjectDeselect handlerObjectDeselect = null; | 7968 | ObjectDeselect handlerObjectDeselect = null; |
7385 | 7969 | uint objID; | |
7386 | for (int i = 0; i < incomingdeselect.ObjectData.Length; i++) | 7970 | for (int i = 0; i < incomingdeselect.ObjectData.Length; i++) |
7387 | { | 7971 | { |
7972 | objID = incomingdeselect.ObjectData[i].ObjectLocalID; | ||
7973 | |||
7388 | handlerObjectDeselect = OnObjectDeselect; | 7974 | handlerObjectDeselect = OnObjectDeselect; |
7389 | if (handlerObjectDeselect != null) | 7975 | if (handlerObjectDeselect != null) |
7390 | { | 7976 | { |
7391 | OnObjectDeselect(incomingdeselect.ObjectData[i].ObjectLocalID, this); | 7977 | OnObjectDeselect(objID, this); |
7392 | } | 7978 | } |
7393 | } | 7979 | } |
7394 | return true; | 7980 | return true; |
@@ -7511,7 +8097,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7511 | physdata.Bounce = phsblock.Restitution; | 8097 | physdata.Bounce = phsblock.Restitution; |
7512 | physdata.Density = phsblock.Density; | 8098 | physdata.Density = phsblock.Density; |
7513 | physdata.Friction = phsblock.Friction; | 8099 | physdata.Friction = phsblock.Friction; |
7514 | physdata.GravitationModifier = phsblock.GravityMultiplier; | 8100 | physdata.GravitationModifier = phsblock.GravityMultiplier; |
7515 | } | 8101 | } |
7516 | 8102 | ||
7517 | handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); | 8103 | handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); |
@@ -7519,19 +8105,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7519 | return true; | 8105 | return true; |
7520 | } | 8106 | } |
7521 | 8107 | ||
8108 | Dictionary<uint, uint> objImageSeqs = null; | ||
8109 | double lastobjImageSeqsMS = 0.0; | ||
8110 | |||
7522 | private bool HandleObjectImage(IClientAPI sender, Packet Pack) | 8111 | private bool HandleObjectImage(IClientAPI sender, Packet Pack) |
7523 | { | 8112 | { |
7524 | ObjectImagePacket imagePack = (ObjectImagePacket)Pack; | 8113 | ObjectImagePacket imagePack = (ObjectImagePacket)Pack; |
7525 | 8114 | ||
7526 | UpdatePrimTexture handlerUpdatePrimTexture = null; | 8115 | UpdatePrimTexture handlerUpdatePrimTexture = OnUpdatePrimTexture; |
8116 | if (handlerUpdatePrimTexture == null) | ||
8117 | return true; | ||
8118 | |||
8119 | double now = Util.GetTimeStampMS(); | ||
8120 | if(objImageSeqs == null || ( now - lastobjImageSeqsMS > 30000.0)) | ||
8121 | { | ||
8122 | objImageSeqs = null; // yeah i know superstition... | ||
8123 | objImageSeqs = new Dictionary<uint, uint>(16); | ||
8124 | } | ||
8125 | |||
8126 | lastobjImageSeqsMS = now; | ||
8127 | uint seq = Pack.Header.Sequence; | ||
8128 | uint id; | ||
8129 | uint lastseq; | ||
8130 | |||
8131 | ObjectImagePacket.ObjectDataBlock o; | ||
7527 | for (int i = 0; i < imagePack.ObjectData.Length; i++) | 8132 | for (int i = 0; i < imagePack.ObjectData.Length; i++) |
7528 | { | 8133 | { |
7529 | handlerUpdatePrimTexture = OnUpdatePrimTexture; | 8134 | o = imagePack.ObjectData[i]; |
7530 | if (handlerUpdatePrimTexture != null) | 8135 | id = o.ObjectLocalID; |
7531 | { | 8136 | if(objImageSeqs.TryGetValue(id, out lastseq)) |
7532 | handlerUpdatePrimTexture(imagePack.ObjectData[i].ObjectLocalID, | 8137 | { |
7533 | imagePack.ObjectData[i].TextureEntry, this); | 8138 | if(seq <= lastseq) |
7534 | } | 8139 | continue; |
8140 | } | ||
8141 | objImageSeqs[id] = seq; | ||
8142 | handlerUpdatePrimTexture(id, o.TextureEntry, this); | ||
7535 | } | 8143 | } |
7536 | return true; | 8144 | return true; |
7537 | } | 8145 | } |
@@ -7605,6 +8213,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7605 | touchArgs.Add(arg); | 8213 | touchArgs.Add(arg); |
7606 | } | 8214 | } |
7607 | } | 8215 | } |
8216 | |||
7608 | handlerGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial, | 8217 | handlerGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial, |
7609 | grabUpdate.ObjectData.GrabPosition, this, touchArgs); | 8218 | grabUpdate.ObjectData.GrabPosition, this, touchArgs); |
7610 | } | 8219 | } |
@@ -7921,10 +8530,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
7921 | handlerObjectDuplicateOnRay = OnObjectDuplicateOnRay; | 8530 | handlerObjectDuplicateOnRay = OnObjectDuplicateOnRay; |
7922 | if (handlerObjectDuplicateOnRay != null) | 8531 | if (handlerObjectDuplicateOnRay != null) |
7923 | { | 8532 | { |
7924 | handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, dupeOnRay.AgentData.DuplicateFlags, | 8533 | |
7925 | AgentId, ActiveGroupId, dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd, | 8534 | UUID rezGroupID = dupeOnRay.AgentData.GroupID; |
7926 | dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, dupeOnRay.AgentData.RayEndIsIntersection, | 8535 | if(!IsGroupMember(rezGroupID)) |
7927 | dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates); | 8536 | rezGroupID = UUID.Zero; |
8537 | |||
8538 | handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, | ||
8539 | dupeOnRay.AgentData.DuplicateFlags, AgentId, rezGroupID, | ||
8540 | dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd, | ||
8541 | dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, | ||
8542 | dupeOnRay.AgentData.RayEndIsIntersection, | ||
8543 | dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates); | ||
7928 | } | 8544 | } |
7929 | } | 8545 | } |
7930 | 8546 | ||
@@ -9106,7 +9722,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9106 | if ((locX >= m_scene.RegionInfo.WorldLocX) | 9722 | if ((locX >= m_scene.RegionInfo.WorldLocX) |
9107 | && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX)) | 9723 | && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX)) |
9108 | && (locY >= m_scene.RegionInfo.WorldLocY) | 9724 | && (locY >= m_scene.RegionInfo.WorldLocY) |
9109 | && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)) ) | 9725 | && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY))) |
9110 | { | 9726 | { |
9111 | tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle; | 9727 | tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle; |
9112 | tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX; | 9728 | tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX; |
@@ -9131,6 +9747,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9131 | 9747 | ||
9132 | private bool HandleUUIDNameRequest(IClientAPI sender, Packet Pack) | 9748 | private bool HandleUUIDNameRequest(IClientAPI sender, Packet Pack) |
9133 | { | 9749 | { |
9750 | ScenePresence sp = (ScenePresence)SceneAgent; | ||
9751 | if(sp == null || sp.IsDeleted || (sp.IsInTransit && !sp.IsInLocalTransit)) | ||
9752 | return true; | ||
9753 | |||
9134 | UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack; | 9754 | UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack; |
9135 | 9755 | ||
9136 | foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock) | 9756 | foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock) |
@@ -9148,13 +9768,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9148 | 9768 | ||
9149 | private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) | 9769 | private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) |
9150 | { | 9770 | { |
9151 | RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; | ||
9152 | |||
9153 | RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; | 9771 | RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; |
9772 | |||
9154 | if (handlerRegionHandleRequest != null) | 9773 | if (handlerRegionHandleRequest != null) |
9155 | { | 9774 | { |
9775 | RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; | ||
9156 | handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); | 9776 | handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); |
9157 | } | 9777 | } |
9778 | |||
9158 | return true; | 9779 | return true; |
9159 | } | 9780 | } |
9160 | 9781 | ||
@@ -9730,6 +10351,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9730 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | 10351 | if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) |
9731 | { | 10352 | { |
9732 | int estateAccessType = Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[1].Parameter)); | 10353 | int estateAccessType = Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[1].Parameter)); |
10354 | |||
9733 | OnUpdateEstateAccessDeltaRequest(this, messagePacket.MethodData.Invoice, estateAccessType, new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter))); | 10355 | OnUpdateEstateAccessDeltaRequest(this, messagePacket.MethodData.Invoice, estateAccessType, new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter))); |
9734 | 10356 | ||
9735 | } | 10357 | } |
@@ -9765,7 +10387,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9765 | Message = Utils.BytesToString(messagePacket.ParamList[1].Parameter); | 10387 | Message = Utils.BytesToString(messagePacket.ParamList[1].Parameter); |
9766 | } | 10388 | } |
9767 | else | 10389 | else |
9768 | { | 10390 | { |
9769 | SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter)); | 10391 | SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter)); |
9770 | SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter); | 10392 | SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter); |
9771 | Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter); | 10393 | Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter); |
@@ -9907,7 +10529,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9907 | return true; | 10529 | return true; |
9908 | 10530 | ||
9909 | case "kickestate": | 10531 | case "kickestate": |
9910 | 10532 | ||
9911 | if(((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) | 10533 | if(((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) |
9912 | { | 10534 | { |
9913 | UUID invoice = messagePacket.MethodData.Invoice; | 10535 | UUID invoice = messagePacket.MethodData.Invoice; |
@@ -9986,6 +10608,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9986 | private bool HandleRequestGodlikePowers(IClientAPI sender, Packet Pack) | 10608 | private bool HandleRequestGodlikePowers(IClientAPI sender, Packet Pack) |
9987 | { | 10609 | { |
9988 | RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack; | 10610 | RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack; |
10611 | |||
10612 | if (rglpPack.AgentData.SessionID != SessionId || | ||
10613 | rglpPack.AgentData.AgentID != AgentId) | ||
10614 | return true; | ||
10615 | |||
9989 | RequestGodlikePowersPacket.RequestBlockBlock rblock = rglpPack.RequestBlock; | 10616 | RequestGodlikePowersPacket.RequestBlockBlock rblock = rglpPack.RequestBlock; |
9990 | UUID token = rblock.Token; | 10617 | UUID token = rblock.Token; |
9991 | 10618 | ||
@@ -9995,7 +10622,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
9995 | 10622 | ||
9996 | if (handlerReqGodlikePowers != null) | 10623 | if (handlerReqGodlikePowers != null) |
9997 | { | 10624 | { |
9998 | handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike, this); | 10625 | handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike); |
9999 | } | 10626 | } |
10000 | 10627 | ||
10001 | return true; | 10628 | return true; |
@@ -10006,6 +10633,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10006 | GodUpdateRegionInfoPacket GodUpdateRegionInfo = | 10633 | GodUpdateRegionInfoPacket GodUpdateRegionInfo = |
10007 | (GodUpdateRegionInfoPacket)Packet; | 10634 | (GodUpdateRegionInfoPacket)Packet; |
10008 | 10635 | ||
10636 | if (GodUpdateRegionInfo.AgentData.SessionID != SessionId || | ||
10637 | GodUpdateRegionInfo.AgentData.AgentID != AgentId) | ||
10638 | return true; | ||
10639 | |||
10009 | GodUpdateRegionInfoUpdate handlerGodUpdateRegionInfo = OnGodUpdateRegionInfoUpdate; | 10640 | GodUpdateRegionInfoUpdate handlerGodUpdateRegionInfo = OnGodUpdateRegionInfoUpdate; |
10010 | if (handlerGodUpdateRegionInfo != null) | 10641 | if (handlerGodUpdateRegionInfo != null) |
10011 | { | 10642 | { |
@@ -10039,6 +10670,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10039 | GodlikeMessagePacket GodlikeMessage = | 10670 | GodlikeMessagePacket GodlikeMessage = |
10040 | (GodlikeMessagePacket)Packet; | 10671 | (GodlikeMessagePacket)Packet; |
10041 | 10672 | ||
10673 | if (GodlikeMessage.AgentData.SessionID != SessionId || | ||
10674 | GodlikeMessage.AgentData.AgentID != AgentId) | ||
10675 | return true; | ||
10676 | |||
10042 | GodlikeMessage handlerGodlikeMessage = onGodlikeMessage; | 10677 | GodlikeMessage handlerGodlikeMessage = onGodlikeMessage; |
10043 | if (handlerGodlikeMessage != null) | 10678 | if (handlerGodlikeMessage != null) |
10044 | { | 10679 | { |
@@ -10055,6 +10690,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10055 | { | 10690 | { |
10056 | StateSavePacket SaveStateMessage = | 10691 | StateSavePacket SaveStateMessage = |
10057 | (StateSavePacket)Packet; | 10692 | (StateSavePacket)Packet; |
10693 | |||
10694 | if (SaveStateMessage.AgentData.SessionID != SessionId || | ||
10695 | SaveStateMessage.AgentData.AgentID != AgentId) | ||
10696 | return true; | ||
10697 | |||
10058 | SaveStateHandler handlerSaveStatePacket = OnSaveState; | 10698 | SaveStateHandler handlerSaveStatePacket = OnSaveState; |
10059 | if (handlerSaveStatePacket != null) | 10699 | if (handlerSaveStatePacket != null) |
10060 | { | 10700 | { |
@@ -10068,30 +10708,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10068 | { | 10708 | { |
10069 | GodKickUserPacket gkupack = (GodKickUserPacket)Pack; | 10709 | GodKickUserPacket gkupack = (GodKickUserPacket)Pack; |
10070 | 10710 | ||
10071 | if (gkupack.UserInfo.GodSessionID == SessionId && AgentId == gkupack.UserInfo.GodID) | 10711 | if (gkupack.UserInfo.GodSessionID != SessionId || |
10072 | { | 10712 | gkupack.UserInfo.GodID != AgentId) |
10073 | GodKickUser handlerGodKickUser = OnGodKickUser; | 10713 | return true; |
10074 | if (handlerGodKickUser != null) | 10714 | |
10075 | { | 10715 | GodKickUser handlerGodKickUser = OnGodKickUser; |
10076 | handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.GodSessionID, | 10716 | if (handlerGodKickUser != null) |
10077 | gkupack.UserInfo.AgentID, gkupack.UserInfo.KickFlags, gkupack.UserInfo.Reason); | ||
10078 | } | ||
10079 | } | ||
10080 | else | ||
10081 | { | 10717 | { |
10082 | SendAgentAlertMessage("Kick request denied", false); | 10718 | handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.AgentID, gkupack.UserInfo.KickFlags, gkupack.UserInfo.Reason); |
10083 | } | 10719 | } |
10084 | //KickUserPacket kupack = new KickUserPacket(); | ||
10085 | //KickUserPacket.UserInfoBlock kupackib = kupack.UserInfo; | ||
10086 | |||
10087 | //kupack.UserInfo.AgentID = gkupack.UserInfo.AgentID; | ||
10088 | //kupack.UserInfo.SessionID = gkupack.UserInfo.GodSessionID; | ||
10089 | 10720 | ||
10090 | //kupack.TargetBlock.TargetIP = (uint)0; | ||
10091 | //kupack.TargetBlock.TargetPort = (ushort)0; | ||
10092 | //kupack.UserInfo.Reason = gkupack.UserInfo.Reason; | ||
10093 | |||
10094 | //OutPacket(kupack, ThrottleOutPacketType.Task); | ||
10095 | return true; | 10721 | return true; |
10096 | } | 10722 | } |
10097 | #endregion GodPackets | 10723 | #endregion GodPackets |
@@ -10410,9 +11036,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10410 | } | 11036 | } |
10411 | else | 11037 | else |
10412 | { | 11038 | { |
10413 | SendUseCachedMuteList(); | 11039 | if(muteListRequest.MuteData.MuteCRC == 0) |
11040 | SendEmpytMuteList(); | ||
11041 | else | ||
11042 | SendUseCachedMuteList(); | ||
10414 | } | 11043 | } |
10415 | return true; | 11044 | return true; |
10416 | } | 11045 | } |
10417 | 11046 | ||
10418 | private bool HandleUpdateMuteListEntry(IClientAPI client, Packet Packet) | 11047 | private bool HandleUpdateMuteListEntry(IClientAPI client, Packet Packet) |
@@ -10425,7 +11054,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10425 | handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, | 11054 | handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, |
10426 | Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), | 11055 | Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), |
10427 | UpdateMuteListEntry.MuteData.MuteType, | 11056 | UpdateMuteListEntry.MuteData.MuteType, |
10428 | UpdateMuteListEntry.AgentData.AgentID); | 11057 | UpdateMuteListEntry.MuteData.MuteFlags); |
10429 | return true; | 11058 | return true; |
10430 | } | 11059 | } |
10431 | return false; | 11060 | return false; |
@@ -10440,8 +11069,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10440 | { | 11069 | { |
10441 | handlerRemoveMuteListEntry(this, | 11070 | handlerRemoveMuteListEntry(this, |
10442 | RemoveMuteListEntry.MuteData.MuteID, | 11071 | RemoveMuteListEntry.MuteData.MuteID, |
10443 | Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), | 11072 | Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName)); |
10444 | RemoveMuteListEntry.AgentData.AgentID); | ||
10445 | return true; | 11073 | return true; |
10446 | } | 11074 | } |
10447 | return false; | 11075 | return false; |
@@ -10485,16 +11113,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10485 | return false; | 11113 | return false; |
10486 | } | 11114 | } |
10487 | 11115 | ||
11116 | private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet) | ||
11117 | { | ||
11118 | ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags = | ||
11119 | (ChangeInventoryItemFlagsPacket)packet; | ||
11120 | ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags; | ||
11121 | if (handlerChangeInventoryItemFlags != null) | ||
11122 | { | ||
11123 | foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData) | ||
11124 | handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags); | ||
11125 | return true; | ||
11126 | } | ||
11127 | return false; | ||
11128 | } | ||
11129 | |||
10488 | private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) | 11130 | private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) |
10489 | { | 11131 | { |
10490 | return true; | 11132 | return true; |
10491 | } | 11133 | } |
10492 | 11134 | ||
11135 | private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack) | ||
11136 | { | ||
11137 | CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack; | ||
11138 | |||
11139 | #region Packet Session and User Check | ||
11140 | if (m_checkPackets) | ||
11141 | { | ||
11142 | if (packet.AgentData.SessionID != SessionId || | ||
11143 | packet.AgentData.AgentID != AgentId) | ||
11144 | return true; | ||
11145 | } | ||
11146 | #endregion | ||
11147 | MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null; | ||
11148 | List<InventoryItemBase> items = new List<InventoryItemBase>(); | ||
11149 | foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData) | ||
11150 | { | ||
11151 | InventoryItemBase b = new InventoryItemBase(); | ||
11152 | b.ID = n.OldItemID; | ||
11153 | b.Folder = n.OldFolderID; | ||
11154 | items.Add(b); | ||
11155 | } | ||
11156 | |||
11157 | handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy; | ||
11158 | if (handlerMoveItemsAndLeaveCopy != null) | ||
11159 | { | ||
11160 | handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID); | ||
11161 | } | ||
11162 | |||
11163 | return true; | ||
11164 | } | ||
11165 | |||
10493 | private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) | 11166 | private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) |
10494 | { | 11167 | { |
10495 | return true; | 11168 | return true; |
10496 | } | 11169 | } |
10497 | 11170 | ||
11171 | |||
10498 | private bool HandleInventoryDescendents(IClientAPI sender, Packet Pack) | 11172 | private bool HandleInventoryDescendents(IClientAPI sender, Packet Pack) |
10499 | { | 11173 | { |
10500 | return true; | 11174 | return true; |
@@ -10748,7 +11422,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10748 | if (m_GroupsModule != null) | 11422 | if (m_GroupsModule != null) |
10749 | { | 11423 | { |
10750 | m_GroupsModule.ActivateGroup(this, activateGroupPacket.AgentData.GroupID); | 11424 | m_GroupsModule.ActivateGroup(this, activateGroupPacket.AgentData.GroupID); |
10751 | m_GroupsModule.SendAgentGroupDataUpdate(this); | ||
10752 | } | 11425 | } |
10753 | return true; | 11426 | return true; |
10754 | 11427 | ||
@@ -10873,11 +11546,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10873 | } | 11546 | } |
10874 | return true; | 11547 | return true; |
10875 | } | 11548 | } |
11549 | |||
11550 | UUID lastGroupProfileRequestID = UUID.Zero; | ||
11551 | double lastGroupProfileRequestTS = Util.GetTimeStampMS(); | ||
11552 | |||
10876 | private bool HandleGroupProfileRequest(IClientAPI sender, Packet Pack) | 11553 | private bool HandleGroupProfileRequest(IClientAPI sender, Packet Pack) |
10877 | { | 11554 | { |
11555 | if(m_GroupsModule == null) | ||
11556 | return true; | ||
11557 | |||
10878 | GroupProfileRequestPacket groupProfileRequest = | 11558 | GroupProfileRequestPacket groupProfileRequest = |
10879 | (GroupProfileRequestPacket)Pack; | 11559 | (GroupProfileRequestPacket)Pack; |
10880 | 11560 | ||
11561 | |||
10881 | #region Packet Session and User Check | 11562 | #region Packet Session and User Check |
10882 | if (m_checkPackets) | 11563 | if (m_checkPackets) |
10883 | { | 11564 | { |
@@ -10887,36 +11568,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10887 | } | 11568 | } |
10888 | #endregion | 11569 | #endregion |
10889 | 11570 | ||
10890 | if (m_GroupsModule != null) | 11571 | UUID grpID = groupProfileRequest.GroupData.GroupID; |
10891 | { | 11572 | double ts = Util.GetTimeStampMS(); |
10892 | GroupProfileReplyPacket groupProfileReply = (GroupProfileReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupProfileReply); | 11573 | if(grpID == lastGroupProfileRequestID && ts - lastGroupProfileRequestTS < 10000) |
11574 | return true; | ||
10893 | 11575 | ||
10894 | groupProfileReply.AgentData = new GroupProfileReplyPacket.AgentDataBlock(); | 11576 | lastGroupProfileRequestID = grpID; |
10895 | groupProfileReply.GroupData = new GroupProfileReplyPacket.GroupDataBlock(); | 11577 | lastGroupProfileRequestTS = ts; |
10896 | groupProfileReply.AgentData.AgentID = AgentId; | ||
10897 | 11578 | ||
10898 | GroupProfileData d = m_GroupsModule.GroupProfileRequest(this, | 11579 | GroupProfileReplyPacket groupProfileReply = (GroupProfileReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupProfileReply); |
10899 | groupProfileRequest.GroupData.GroupID); | ||
10900 | 11580 | ||
10901 | groupProfileReply.GroupData.GroupID = d.GroupID; | 11581 | groupProfileReply.AgentData = new GroupProfileReplyPacket.AgentDataBlock(); |
10902 | groupProfileReply.GroupData.Name = Util.StringToBytes256(d.Name); | 11582 | groupProfileReply.GroupData = new GroupProfileReplyPacket.GroupDataBlock(); |
10903 | groupProfileReply.GroupData.Charter = Util.StringToBytes1024(d.Charter); | 11583 | groupProfileReply.AgentData.AgentID = AgentId; |
10904 | groupProfileReply.GroupData.ShowInList = d.ShowInList; | ||
10905 | groupProfileReply.GroupData.MemberTitle = Util.StringToBytes256(d.MemberTitle); | ||
10906 | groupProfileReply.GroupData.PowersMask = d.PowersMask; | ||
10907 | groupProfileReply.GroupData.InsigniaID = d.InsigniaID; | ||
10908 | groupProfileReply.GroupData.FounderID = d.FounderID; | ||
10909 | groupProfileReply.GroupData.MembershipFee = d.MembershipFee; | ||
10910 | groupProfileReply.GroupData.OpenEnrollment = d.OpenEnrollment; | ||
10911 | groupProfileReply.GroupData.Money = d.Money; | ||
10912 | groupProfileReply.GroupData.GroupMembershipCount = d.GroupMembershipCount; | ||
10913 | groupProfileReply.GroupData.GroupRolesCount = d.GroupRolesCount; | ||
10914 | groupProfileReply.GroupData.AllowPublish = d.AllowPublish; | ||
10915 | groupProfileReply.GroupData.MaturePublish = d.MaturePublish; | ||
10916 | groupProfileReply.GroupData.OwnerRole = d.OwnerRole; | ||
10917 | 11584 | ||
10918 | OutPacket(groupProfileReply, ThrottleOutPacketType.Task); | 11585 | GroupProfileData d = m_GroupsModule.GroupProfileRequest(this, |
11586 | groupProfileRequest.GroupData.GroupID); | ||
11587 | |||
11588 | if(d.GroupID == UUID.Zero) // don't send broken data | ||
11589 | return true; | ||
11590 | |||
11591 | groupProfileReply.GroupData.GroupID = d.GroupID; | ||
11592 | groupProfileReply.GroupData.Name = Util.StringToBytes256(d.Name); | ||
11593 | groupProfileReply.GroupData.Charter = Util.StringToBytes1024(d.Charter); | ||
11594 | groupProfileReply.GroupData.ShowInList = d.ShowInList; | ||
11595 | groupProfileReply.GroupData.MemberTitle = Util.StringToBytes256(d.MemberTitle); | ||
11596 | groupProfileReply.GroupData.PowersMask = d.PowersMask; | ||
11597 | groupProfileReply.GroupData.InsigniaID = d.InsigniaID; | ||
11598 | groupProfileReply.GroupData.FounderID = d.FounderID; | ||
11599 | groupProfileReply.GroupData.MembershipFee = d.MembershipFee; | ||
11600 | groupProfileReply.GroupData.OpenEnrollment = d.OpenEnrollment; | ||
11601 | groupProfileReply.GroupData.Money = d.Money; | ||
11602 | groupProfileReply.GroupData.GroupMembershipCount = d.GroupMembershipCount; | ||
11603 | groupProfileReply.GroupData.GroupRolesCount = d.GroupRolesCount; | ||
11604 | groupProfileReply.GroupData.AllowPublish = d.AllowPublish; | ||
11605 | groupProfileReply.GroupData.MaturePublish = d.MaturePublish; | ||
11606 | groupProfileReply.GroupData.OwnerRole = d.OwnerRole; | ||
11607 | |||
11608 | Scene scene = (Scene)m_scene; | ||
11609 | if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID))) | ||
11610 | { | ||
11611 | ScenePresence p; | ||
11612 | if (scene.TryGetScenePresence(sender.AgentId, out p)) | ||
11613 | { | ||
11614 | if (p.IsViewerUIGod) | ||
11615 | { | ||
11616 | groupProfileReply.GroupData.OpenEnrollment = true; | ||
11617 | groupProfileReply.GroupData.MembershipFee = 0; | ||
11618 | } | ||
11619 | } | ||
10919 | } | 11620 | } |
11621 | |||
11622 | OutPacket(groupProfileReply, ThrottleOutPacketType.Task); | ||
11623 | |||
11624 | if(grpID == lastGroupProfileRequestID) | ||
11625 | lastGroupProfileRequestTS = Util.GetTimeStampMS() - 7000; | ||
11626 | |||
10920 | return true; | 11627 | return true; |
10921 | } | 11628 | } |
10922 | private bool HandleGroupMembersRequest(IClientAPI sender, Packet Pack) | 11629 | private bool HandleGroupMembersRequest(IClientAPI sender, Packet Pack) |
@@ -10939,12 +11646,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10939 | m_GroupsModule.GroupMembersRequest(this, groupMembersRequestPacket.GroupData.GroupID); | 11646 | m_GroupsModule.GroupMembersRequest(this, groupMembersRequestPacket.GroupData.GroupID); |
10940 | 11647 | ||
10941 | int memberCount = members.Count; | 11648 | int memberCount = members.Count; |
10942 | 11649 | int indx = 0; | |
10943 | while (true) | 11650 | while (indx < memberCount) |
10944 | { | 11651 | { |
10945 | int blockCount = members.Count; | 11652 | int blockCount = memberCount - indx; |
10946 | if (blockCount > 40) | 11653 | if (blockCount > 25) |
10947 | blockCount = 40; | 11654 | blockCount = 25; |
10948 | 11655 | ||
10949 | GroupMembersReplyPacket groupMembersReply = (GroupMembersReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupMembersReply); | 11656 | GroupMembersReplyPacket groupMembersReply = (GroupMembersReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupMembersReply); |
10950 | 11657 | ||
@@ -10965,8 +11672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10965 | 11672 | ||
10966 | for (int i = 0; i < blockCount; i++) | 11673 | for (int i = 0; i < blockCount; i++) |
10967 | { | 11674 | { |
10968 | GroupMembersData m = members[0]; | 11675 | GroupMembersData m = members[indx++]; |
10969 | members.RemoveAt(0); | ||
10970 | 11676 | ||
10971 | groupMembersReply.MemberData[i] = | 11677 | groupMembersReply.MemberData[i] = |
10972 | new GroupMembersReplyPacket.MemberDataBlock(); | 11678 | new GroupMembersReplyPacket.MemberDataBlock(); |
@@ -10984,8 +11690,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10984 | m.IsOwner; | 11690 | m.IsOwner; |
10985 | } | 11691 | } |
10986 | OutPacket(groupMembersReply, ThrottleOutPacketType.Task); | 11692 | OutPacket(groupMembersReply, ThrottleOutPacketType.Task); |
10987 | if (members.Count == 0) | ||
10988 | return true; | ||
10989 | } | 11693 | } |
10990 | } | 11694 | } |
10991 | return true; | 11695 | return true; |
@@ -11488,11 +12192,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11488 | 12192 | ||
11489 | StartLure handlerStartLure = OnStartLure; | 12193 | StartLure handlerStartLure = OnStartLure; |
11490 | if (handlerStartLure != null) | 12194 | if (handlerStartLure != null) |
11491 | handlerStartLure(startLureRequest.Info.LureType, | 12195 | { |
11492 | Utils.BytesToString( | 12196 | for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++) |
11493 | startLureRequest.Info.Message), | 12197 | { |
11494 | startLureRequest.TargetData[0].TargetID, | 12198 | handlerStartLure(startLureRequest.Info.LureType, |
11495 | this); | 12199 | Utils.BytesToString( |
12200 | startLureRequest.Info.Message), | ||
12201 | startLureRequest.TargetData[i].TargetID, | ||
12202 | this); | ||
12203 | } | ||
12204 | } | ||
11496 | return true; | 12205 | return true; |
11497 | } | 12206 | } |
11498 | private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) | 12207 | private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) |
@@ -11606,10 +12315,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11606 | } | 12315 | } |
11607 | #endregion | 12316 | #endregion |
11608 | 12317 | ||
11609 | ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; | 12318 | ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; |
11610 | if (handlerClassifiedGodDelete != null) | 12319 | if (handlerClassifiedGodDelete != null) |
11611 | handlerClassifiedGodDelete( | 12320 | handlerClassifiedGodDelete( |
11612 | classifiedGodDelete.Data.ClassifiedID, | 12321 | classifiedGodDelete.Data.ClassifiedID, |
12322 | classifiedGodDelete.Data.QueryID, | ||
11613 | this); | 12323 | this); |
11614 | return true; | 12324 | return true; |
11615 | } | 12325 | } |
@@ -11833,6 +12543,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11833 | return true; | 12543 | return true; |
11834 | } | 12544 | } |
11835 | 12545 | ||
12546 | private bool HandleRevokePermissions(IClientAPI sender, Packet Pack) | ||
12547 | { | ||
12548 | RevokePermissionsPacket pkt = (RevokePermissionsPacket)Pack; | ||
12549 | if (pkt.AgentData.SessionID != SessionId || | ||
12550 | pkt .AgentData.AgentID != AgentId) | ||
12551 | return true; | ||
12552 | |||
12553 | // don't use multidelegate "event" | ||
12554 | ScenePresence sp = (ScenePresence)SceneAgent; | ||
12555 | if(sp != null && !sp.IsDeleted && !sp.IsInTransit) | ||
12556 | { | ||
12557 | UUID objectID = pkt.Data.ObjectID; | ||
12558 | uint permissions = pkt.Data.ObjectPermissions; | ||
12559 | |||
12560 | sp.HandleRevokePermissions(objectID , permissions); | ||
12561 | } | ||
12562 | return true; | ||
12563 | } | ||
11836 | private bool HandlePlacesQuery(IClientAPI sender, Packet Pack) | 12564 | private bool HandlePlacesQuery(IClientAPI sender, Packet Pack) |
11837 | { | 12565 | { |
11838 | PlacesQueryPacket placesQueryPacket = | 12566 | PlacesQueryPacket placesQueryPacket = |
@@ -11865,7 +12593,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11865 | scriptQuestion.Data.Questions = question; | 12593 | scriptQuestion.Data.Questions = question; |
11866 | scriptQuestion.Data.ObjectName = Util.StringToBytes256(taskName); | 12594 | scriptQuestion.Data.ObjectName = Util.StringToBytes256(taskName); |
11867 | scriptQuestion.Data.ObjectOwner = Util.StringToBytes256(ownerName); | 12595 | scriptQuestion.Data.ObjectOwner = Util.StringToBytes256(ownerName); |
11868 | 12596 | ||
11869 | OutPacket(scriptQuestion, ThrottleOutPacketType.Task); | 12597 | OutPacket(scriptQuestion, ThrottleOutPacketType.Task); |
11870 | } | 12598 | } |
11871 | 12599 | ||
@@ -11912,86 +12640,52 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11912 | /// <param name="simclient"></param> | 12640 | /// <param name="simclient"></param> |
11913 | /// <param name="packet"></param> | 12641 | /// <param name="packet"></param> |
11914 | /// <returns></returns> | 12642 | /// <returns></returns> |
12643 | |||
11915 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | 12644 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) |
11916 | { | 12645 | { |
12646 | //m_log.Debug("texture cached: " + packet.ToString()); | ||
11917 | AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; | 12647 | AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; |
11918 | AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); | 12648 | AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); |
11919 | 12649 | ||
11920 | if (cachedtex.AgentData.SessionID != SessionId) | 12650 | if (cachedtex.AgentData.SessionID != SessionId) |
11921 | return false; | 12651 | return false; |
11922 | 12652 | ||
11923 | |||
11924 | // TODO: don't create new blocks if recycling an old packet | 12653 | // TODO: don't create new blocks if recycling an old packet |
11925 | cachedresp.AgentData.AgentID = AgentId; | 12654 | cachedresp.AgentData.AgentID = AgentId; |
11926 | cachedresp.AgentData.SessionID = m_sessionId; | 12655 | cachedresp.AgentData.SessionID = m_sessionId; |
11927 | cachedresp.AgentData.SerialNum = m_cachedTextureSerial; | 12656 | cachedresp.AgentData.SerialNum = cachedtex.AgentData.SerialNum; |
11928 | m_cachedTextureSerial++; | ||
11929 | cachedresp.WearableData = | 12657 | cachedresp.WearableData = |
11930 | new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; | 12658 | new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; |
11931 | 12659 | ||
11932 | int maxWearablesLoop = cachedtex.WearableData.Length; | 12660 | int cacheHits = 0; |
11933 | if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES) | ||
11934 | maxWearablesLoop = AvatarWearable.MAX_WEARABLES; | ||
11935 | 12661 | ||
11936 | // Find the cached baked textures for this user, if they're available | 12662 | // We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid |
11937 | 12663 | ||
11938 | IAssetService cache = m_scene.AssetService; | ||
11939 | IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>(); | ||
11940 | |||
11941 | WearableCacheItem[] cacheItems = null; | 12664 | WearableCacheItem[] cacheItems = null; |
11942 | 12665 | ||
11943 | if (bakedTextureModule != null && cache != null) | 12666 | ScenePresence p = m_scene.GetScenePresence(AgentId); |
11944 | { | ||
11945 | ScenePresence p = m_scene.GetScenePresence(AgentId); | ||
11946 | if (p.Appearance != null) | ||
11947 | { | ||
11948 | if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty) | ||
11949 | { | ||
11950 | try | ||
11951 | { | ||
11952 | cacheItems = bakedTextureModule.Get(AgentId); | ||
11953 | p.Appearance.WearableCacheItems = cacheItems; | ||
11954 | p.Appearance.WearableCacheItemsDirty = false; | ||
11955 | } | ||
11956 | catch (Exception) | ||
11957 | { | ||
11958 | cacheItems = null; | ||
11959 | } | ||
11960 | 12667 | ||
11961 | } | 12668 | if (p != null && p.Appearance != null) |
11962 | else if (p.Appearance.WearableCacheItems != null) | 12669 | { |
11963 | { | 12670 | cacheItems = p.Appearance.WearableCacheItems; |
11964 | cacheItems = p.Appearance.WearableCacheItems; | ||
11965 | } | ||
11966 | } | ||
11967 | } | 12671 | } |
11968 | 12672 | ||
12673 | int maxWearablesLoop = cachedtex.WearableData.Length; | ||
12674 | |||
11969 | if (cacheItems != null) | 12675 | if (cacheItems != null) |
11970 | { | 12676 | { |
11971 | // We need to make sure the asset stored in the bake is available on this server also by its assetid before we map it to a Cacheid. | 12677 | if (maxWearablesLoop > cacheItems.Length) |
11972 | // Copy the baked textures to the sim's assets cache (local only). | 12678 | maxWearablesLoop = cacheItems.Length; |
11973 | foreach (WearableCacheItem item in cacheItems) | ||
11974 | { | ||
11975 | if (cache.GetCached(item.TextureID.ToString()) == null) | ||
11976 | { | ||
11977 | item.TextureAsset.Temporary = true; | ||
11978 | item.TextureAsset.Local = true; | ||
11979 | cache.Store(item.TextureAsset); | ||
11980 | } | ||
11981 | } | ||
11982 | |||
11983 | // Return the cached textures | ||
11984 | for (int i = 0; i < maxWearablesLoop; i++) | 12679 | for (int i = 0; i < maxWearablesLoop; i++) |
11985 | { | 12680 | { |
11986 | WearableCacheItem item = | 12681 | int idx = cachedtex.WearableData[i].TextureIndex; |
11987 | WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex, cacheItems); | ||
11988 | |||
11989 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | 12682 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); |
11990 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; | 12683 | cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; |
11991 | cachedresp.WearableData[i].HostName = new byte[0]; | 12684 | cachedresp.WearableData[i].HostName = new byte[0]; |
11992 | if (item != null && cachedtex.WearableData[i].ID == item.CacheId) | 12685 | if (cachedtex.WearableData[i].ID == cacheItems[idx].CacheId) |
11993 | { | 12686 | { |
11994 | cachedresp.WearableData[i].TextureID = item.TextureID; | 12687 | cachedresp.WearableData[i].TextureID = cacheItems[idx].TextureID; |
12688 | cacheHits++; | ||
11995 | } | 12689 | } |
11996 | else | 12690 | else |
11997 | { | 12691 | { |
@@ -12001,7 +12695,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12001 | } | 12695 | } |
12002 | else | 12696 | else |
12003 | { | 12697 | { |
12004 | // Cached textures not available | ||
12005 | for (int i = 0; i < maxWearablesLoop; i++) | 12698 | for (int i = 0; i < maxWearablesLoop; i++) |
12006 | { | 12699 | { |
12007 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | 12700 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); |
@@ -12010,13 +12703,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12010 | cachedresp.WearableData[i].HostName = new byte[0]; | 12703 | cachedresp.WearableData[i].HostName = new byte[0]; |
12011 | } | 12704 | } |
12012 | } | 12705 | } |
12013 | 12706 | ||
12707 | //m_log.DebugFormat("texture cached: hits {0}", cacheHits); | ||
12708 | |||
12014 | cachedresp.Header.Zerocoded = true; | 12709 | cachedresp.Header.Zerocoded = true; |
12015 | OutPacket(cachedresp, ThrottleOutPacketType.Task); | 12710 | OutPacket(cachedresp, ThrottleOutPacketType.Task); |
12016 | 12711 | ||
12017 | return true; | 12712 | return true; |
12018 | } | 12713 | } |
12019 | 12714 | ||
12020 | /// <summary> | 12715 | /// <summary> |
12021 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | 12716 | /// Send a response back to a client when it asks the asset server (via the region server) if it has |
12022 | /// its appearance texture cached. | 12717 | /// its appearance texture cached. |
@@ -12080,209 +12775,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12080 | } | 12775 | } |
12081 | else | 12776 | else |
12082 | { | 12777 | { |
12083 | // m_log.DebugFormat( | 12778 | ClientChangeObject updatehandler = onClientChangeObject; |
12084 | // "[CLIENT]: Processing block {0} type {1} for {2} {3}", | ||
12085 | // i, block.Type, part.Name, part.LocalId); | ||
12086 | 12779 | ||
12087 | // // Do this once since fetch parts creates a new array. | 12780 | if (updatehandler != null) |
12088 | // SceneObjectPart[] parts = part.ParentGroup.Parts; | 12781 | { |
12089 | // for (int j = 0; j < parts.Length; j++) | 12782 | ObjectChangeData udata = new ObjectChangeData(); |
12090 | // { | ||
12091 | // part.StoreUndoState(); | ||
12092 | // parts[j].IgnoreUndoUpdate = true; | ||
12093 | // } | ||
12094 | 12783 | ||
12095 | UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; | 12784 | /*ubit from ll JIRA: |
12785 | * 0x01 position | ||
12786 | * 0x02 rotation | ||
12787 | * 0x04 scale | ||
12096 | 12788 | ||
12097 | switch (block.Type) | 12789 | * 0x08 LINK_SET |
12098 | { | 12790 | * 0x10 UNIFORM for scale |
12099 | case 1: | 12791 | */ |
12100 | Vector3 pos1 = new Vector3(block.Data, 0); | ||
12101 | 12792 | ||
12102 | UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; | 12793 | // translate to internal changes |
12103 | if (handlerUpdatePrimSinglePosition != null) | 12794 | // not all cases .. just the ones older code did |
12104 | { | ||
12105 | // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); | ||
12106 | handlerUpdatePrimSinglePosition(localId, pos1, this); | ||
12107 | } | ||
12108 | break; | ||
12109 | 12795 | ||
12110 | case 2: | 12796 | switch (block.Type) |
12111 | Quaternion rot1 = new Quaternion(block.Data, 0, true); | 12797 | { |
12798 | case 1: //change position sp | ||
12799 | udata.position = new Vector3(block.Data, 0); | ||
12112 | 12800 | ||
12113 | UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; | 12801 | udata.change = ObjectChangeType.primP; |
12114 | if (handlerUpdatePrimSingleRotation != null) | 12802 | updatehandler(localId, udata, this); |
12115 | { | 12803 | break; |
12116 | // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W); | ||
12117 | handlerUpdatePrimSingleRotation(localId, rot1, this); | ||
12118 | } | ||
12119 | break; | ||
12120 | 12804 | ||
12121 | case 3: | 12805 | case 2: // rotation sp |
12122 | Vector3 rotPos = new Vector3(block.Data, 0); | 12806 | udata.rotation = new Quaternion(block.Data, 0, true); |
12123 | Quaternion rot2 = new Quaternion(block.Data, 12, true); | ||
12124 | 12807 | ||
12125 | UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; | 12808 | udata.change = ObjectChangeType.primR; |
12126 | if (handlerUpdatePrimSingleRotationPosition != null) | 12809 | updatehandler(localId, udata, this); |
12127 | { | 12810 | break; |
12128 | // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z); | ||
12129 | // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W); | ||
12130 | handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this); | ||
12131 | } | ||
12132 | break; | ||
12133 | 12811 | ||
12134 | case 4: | 12812 | case 3: // position plus rotation |
12135 | case 20: | 12813 | udata.position = new Vector3(block.Data, 0); |
12136 | Vector3 scale4 = new Vector3(block.Data, 0); | 12814 | udata.rotation = new Quaternion(block.Data, 12, true); |
12137 | 12815 | ||
12138 | UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; | 12816 | udata.change = ObjectChangeType.primPR; |
12139 | if (handlerUpdatePrimScale != null) | 12817 | updatehandler(localId, udata, this); |
12140 | { | 12818 | break; |
12141 | // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z); | ||
12142 | handlerUpdatePrimScale(localId, scale4, this); | ||
12143 | } | ||
12144 | break; | ||
12145 | 12819 | ||
12146 | case 5: | 12820 | case 4: // scale sp |
12147 | Vector3 scale1 = new Vector3(block.Data, 12); | 12821 | udata.scale = new Vector3(block.Data, 0); |
12148 | Vector3 pos11 = new Vector3(block.Data, 0); | 12822 | udata.change = ObjectChangeType.primS; |
12149 | 12823 | ||
12150 | handlerUpdatePrimScale = OnUpdatePrimScale; | 12824 | updatehandler(localId, udata, this); |
12151 | if (handlerUpdatePrimScale != null) | 12825 | break; |
12152 | { | ||
12153 | // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); | ||
12154 | handlerUpdatePrimScale(localId, scale1, this); | ||
12155 | 12826 | ||
12156 | handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; | 12827 | case 0x14: // uniform scale sp |
12157 | if (handlerUpdatePrimSinglePosition != null) | 12828 | udata.scale = new Vector3(block.Data, 0); |
12158 | { | ||
12159 | handlerUpdatePrimSinglePosition(localId, pos11, this); | ||
12160 | } | ||
12161 | } | ||
12162 | break; | ||
12163 | 12829 | ||
12164 | case 9: | 12830 | udata.change = ObjectChangeType.primUS; |
12165 | Vector3 pos2 = new Vector3(block.Data, 0); | 12831 | updatehandler(localId, udata, this); |
12832 | break; | ||
12166 | 12833 | ||
12167 | UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; | 12834 | case 5: // scale and position sp |
12835 | udata.position = new Vector3(block.Data, 0); | ||
12836 | udata.scale = new Vector3(block.Data, 12); | ||
12168 | 12837 | ||
12169 | if (handlerUpdateVector != null) | 12838 | udata.change = ObjectChangeType.primPS; |
12170 | { | 12839 | updatehandler(localId, udata, this); |
12171 | handlerUpdateVector(localId, pos2, this); | 12840 | break; |
12172 | } | ||
12173 | break; | ||
12174 | 12841 | ||
12175 | case 10: | 12842 | case 0x15: //uniform scale and position |
12176 | Quaternion rot3 = new Quaternion(block.Data, 0, true); | 12843 | udata.position = new Vector3(block.Data, 0); |
12844 | udata.scale = new Vector3(block.Data, 12); | ||
12177 | 12845 | ||
12178 | UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; | 12846 | udata.change = ObjectChangeType.primPUS; |
12179 | if (handlerUpdatePrimRotation != null) | 12847 | updatehandler(localId, udata, this); |
12180 | { | 12848 | break; |
12181 | // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W); | ||
12182 | handlerUpdatePrimRotation(localId, rot3, this); | ||
12183 | } | ||
12184 | break; | ||
12185 | 12849 | ||
12186 | case 11: | 12850 | // now group related (bit 4) |
12187 | Vector3 pos3 = new Vector3(block.Data, 0); | 12851 | case 9: //( 8 + 1 )group position |
12188 | Quaternion rot4 = new Quaternion(block.Data, 12, true); | 12852 | udata.position = new Vector3(block.Data, 0); |
12189 | 12853 | ||
12190 | handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; | 12854 | udata.change = ObjectChangeType.groupP; |
12191 | if (handlerUpdatePrimGroupRotation != null) | 12855 | updatehandler(localId, udata, this); |
12192 | { | 12856 | break; |
12193 | // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z); | ||
12194 | // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W); | ||
12195 | handlerUpdatePrimGroupRotation(localId, pos3, rot4, this); | ||
12196 | } | ||
12197 | break; | ||
12198 | case 12: | ||
12199 | case 28: | ||
12200 | Vector3 scale7 = new Vector3(block.Data, 0); | ||
12201 | 12857 | ||
12202 | UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; | 12858 | case 0x0A: // (8 + 2) group rotation |
12203 | if (handlerUpdatePrimGroupScale != null) | 12859 | udata.rotation = new Quaternion(block.Data, 0, true); |
12204 | { | ||
12205 | // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z); | ||
12206 | handlerUpdatePrimGroupScale(localId, scale7, this); | ||
12207 | } | ||
12208 | break; | ||
12209 | 12860 | ||
12210 | case 13: | 12861 | udata.change = ObjectChangeType.groupR; |
12211 | Vector3 scale2 = new Vector3(block.Data, 12); | 12862 | updatehandler(localId, udata, this); |
12212 | Vector3 pos4 = new Vector3(block.Data, 0); | 12863 | break; |
12213 | 12864 | ||
12214 | handlerUpdatePrimScale = OnUpdatePrimScale; | 12865 | case 0x0B: //( 8 + 2 + 1) group rotation and position |
12215 | if (handlerUpdatePrimScale != null) | 12866 | udata.position = new Vector3(block.Data, 0); |
12216 | { | 12867 | udata.rotation = new Quaternion(block.Data, 12, true); |
12217 | //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); | ||
12218 | handlerUpdatePrimScale(localId, scale2, this); | ||
12219 | 12868 | ||
12220 | // Change the position based on scale (for bug number 246) | 12869 | udata.change = ObjectChangeType.groupPR; |
12221 | handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; | 12870 | updatehandler(localId, udata, this); |
12222 | // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); | 12871 | break; |
12223 | if (handlerUpdatePrimSinglePosition != null) | ||
12224 | { | ||
12225 | handlerUpdatePrimSinglePosition(localId, pos4, this); | ||
12226 | } | ||
12227 | } | ||
12228 | break; | ||
12229 | 12872 | ||
12230 | case 29: | 12873 | case 0x0C: // (8 + 4) group scale |
12231 | Vector3 scale5 = new Vector3(block.Data, 12); | 12874 | // only afects root prim and only sent by viewer editor object tab scaling |
12232 | Vector3 pos5 = new Vector3(block.Data, 0); | 12875 | // mouse edition only allows uniform scaling |
12876 | // SL MAY CHANGE THIS in viewers | ||
12233 | 12877 | ||
12234 | handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; | 12878 | udata.scale = new Vector3(block.Data, 0); |
12235 | if (handlerUpdatePrimGroupScale != null) | ||
12236 | { | ||
12237 | // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); | ||
12238 | part.StoreUndoState(true); | ||
12239 | part.IgnoreUndoUpdate = true; | ||
12240 | handlerUpdatePrimGroupScale(localId, scale5, this); | ||
12241 | handlerUpdateVector = OnUpdatePrimGroupPosition; | ||
12242 | 12879 | ||
12243 | if (handlerUpdateVector != null) | 12880 | udata.change = ObjectChangeType.groupS; |
12244 | { | 12881 | updatehandler(localId, udata, this); |
12245 | handlerUpdateVector(localId, pos5, this); | ||
12246 | } | ||
12247 | 12882 | ||
12248 | part.IgnoreUndoUpdate = false; | 12883 | break; |
12249 | } | ||
12250 | 12884 | ||
12251 | break; | 12885 | case 0x0D: //(8 + 4 + 1) group scale and position |
12886 | // exception as above | ||
12252 | 12887 | ||
12253 | case 21: | 12888 | udata.position = new Vector3(block.Data, 0); |
12254 | Vector3 scale6 = new Vector3(block.Data, 12); | 12889 | udata.scale = new Vector3(block.Data, 12); |
12255 | Vector3 pos6 = new Vector3(block.Data, 0); | ||
12256 | 12890 | ||
12257 | handlerUpdatePrimScale = OnUpdatePrimScale; | 12891 | udata.change = ObjectChangeType.groupPS; |
12258 | if (handlerUpdatePrimScale != null) | 12892 | updatehandler(localId, udata, this); |
12259 | { | 12893 | break; |
12260 | part.StoreUndoState(false); | ||
12261 | part.IgnoreUndoUpdate = true; | ||
12262 | 12894 | ||
12263 | // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); | 12895 | case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM |
12264 | handlerUpdatePrimScale(localId, scale6, this); | 12896 | udata.scale = new Vector3(block.Data, 0); |
12265 | handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; | ||
12266 | if (handlerUpdatePrimSinglePosition != null) | ||
12267 | { | ||
12268 | handlerUpdatePrimSinglePosition(localId, pos6, this); | ||
12269 | } | ||
12270 | 12897 | ||
12271 | part.IgnoreUndoUpdate = false; | 12898 | udata.change = ObjectChangeType.groupUS; |
12272 | } | 12899 | updatehandler(localId, udata, this); |
12273 | break; | 12900 | break; |
12274 | 12901 | ||
12275 | default: | 12902 | case 0x1D: // (UNIFORM + GROUP + SCALE + POS) |
12276 | m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); | 12903 | udata.position = new Vector3(block.Data, 0); |
12277 | break; | 12904 | udata.scale = new Vector3(block.Data, 12); |
12905 | |||
12906 | udata.change = ObjectChangeType.groupPUS; | ||
12907 | updatehandler(localId, udata, this); | ||
12908 | break; | ||
12909 | |||
12910 | default: | ||
12911 | m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); | ||
12912 | break; | ||
12913 | } | ||
12278 | } | 12914 | } |
12279 | 12915 | ||
12280 | // for (int j = 0; j < parts.Length; j++) | ||
12281 | // parts[j].IgnoreUndoUpdate = false; | ||
12282 | } | 12916 | } |
12283 | } | 12917 | } |
12284 | } | 12918 | } |
12285 | |||
12286 | return true; | 12919 | return true; |
12287 | } | 12920 | } |
12288 | 12921 | ||
@@ -12342,7 +12975,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12342 | /// <param name="throttles"></param> | 12975 | /// <param name="throttles"></param> |
12343 | public void SetChildAgentThrottle(byte[] throttles) | 12976 | public void SetChildAgentThrottle(byte[] throttles) |
12344 | { | 12977 | { |
12345 | m_udpClient.SetThrottles(throttles); | 12978 | SetChildAgentThrottle(throttles, 1.0f); |
12979 | } | ||
12980 | |||
12981 | public void SetChildAgentThrottle(byte[] throttles,float factor) | ||
12982 | { | ||
12983 | m_udpClient.SetThrottles(throttles, factor); | ||
12984 | GenericCall2 handler = OnUpdateThrottles; | ||
12985 | if (handler != null) | ||
12986 | { | ||
12987 | handler(); | ||
12988 | } | ||
12989 | } | ||
12990 | |||
12991 | /// <summary> | ||
12992 | /// Sets the throttles from values supplied caller | ||
12993 | /// </summary> | ||
12994 | /// <param name="throttles"></param> | ||
12995 | public void SetAgentThrottleSilent(int throttle, int setting) | ||
12996 | { | ||
12997 | m_udpClient.ForceThrottleSetting(throttle,setting); | ||
12998 | } | ||
12999 | |||
13000 | public int GetAgentThrottleSilent(int throttle) | ||
13001 | { | ||
13002 | return m_udpClient.GetThrottleSetting(throttle); | ||
12346 | } | 13003 | } |
12347 | 13004 | ||
12348 | /// <summary> | 13005 | /// <summary> |
@@ -12403,9 +13060,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12403 | /// provide your own method.</param> | 13060 | /// provide your own method.</param> |
12404 | protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) | 13061 | protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) |
12405 | { | 13062 | { |
13063 | |||
13064 | /* this is causing packet loss for some reason | ||
13065 | if(!m_udpClient.IsConnected) | ||
13066 | { | ||
13067 | PacketPool.Instance.ReturnPacket(packet); | ||
13068 | return; | ||
13069 | } | ||
13070 | */ | ||
12406 | if (m_outPacketsToDrop != null) | 13071 | if (m_outPacketsToDrop != null) |
13072 | { | ||
12407 | if (m_outPacketsToDrop.Contains(packet.Type.ToString())) | 13073 | if (m_outPacketsToDrop.Contains(packet.Type.ToString())) |
13074 | { | ||
13075 | PacketPool.Instance.ReturnPacket(packet); | ||
12408 | return; | 13076 | return; |
13077 | } | ||
13078 | } | ||
12409 | 13079 | ||
12410 | if (DebugPacketLevel > 0) | 13080 | if (DebugPacketLevel > 0) |
12411 | { | 13081 | { |
@@ -12424,7 +13094,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12424 | 13094 | ||
12425 | if (DebugPacketLevel <= 100 && (packet.Type == PacketType.AvatarAnimation || packet.Type == PacketType.ViewerEffect)) | 13095 | if (DebugPacketLevel <= 100 && (packet.Type == PacketType.AvatarAnimation || packet.Type == PacketType.ViewerEffect)) |
12426 | logPacket = false; | 13096 | logPacket = false; |
12427 | 13097 | ||
12428 | if (DebugPacketLevel <= 50 | 13098 | if (DebugPacketLevel <= 50 |
12429 | && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) | 13099 | && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) |
12430 | logPacket = false; | 13100 | logPacket = false; |
@@ -12437,7 +13107,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12437 | "[CLIENT]: PACKET OUT to {0} ({1}) in {2} - {3}", | 13107 | "[CLIENT]: PACKET OUT to {0} ({1}) in {2} - {3}", |
12438 | Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type); | 13108 | Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type); |
12439 | } | 13109 | } |
12440 | 13110 | ||
12441 | m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method); | 13111 | m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method); |
12442 | } | 13112 | } |
12443 | 13113 | ||
@@ -12450,8 +13120,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12450 | uint regionY = 0; | 13120 | uint regionY = 0; |
12451 | 13121 | ||
12452 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY); | 13122 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY); |
12453 | locx = Convert.ToSingle(args[0]) - (float)regionX; | 13123 | locx = (float)(Convert.ToDouble(args[0]) - (double)regionX); |
12454 | locy = Convert.ToSingle(args[1]) - (float)regionY; | 13124 | locy = (float)(Convert.ToDouble(args[1]) - (double)regionY); |
12455 | locz = Convert.ToSingle(args[2]); | 13125 | locz = Convert.ToSingle(args[2]); |
12456 | 13126 | ||
12457 | Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo; | 13127 | Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo; |
@@ -12677,20 +13347,75 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12677 | 13347 | ||
12678 | public void RefreshGroupMembership() | 13348 | public void RefreshGroupMembership() |
12679 | { | 13349 | { |
12680 | if (m_GroupsModule != null) | 13350 | lock(m_groupPowers) |
12681 | { | 13351 | { |
12682 | GroupMembershipData[] GroupMembership = | 13352 | GroupMembershipData activeMembership = null; |
13353 | if (m_GroupsModule != null) | ||
13354 | { | ||
13355 | GroupMembershipData[] GroupMembership = | ||
12683 | m_GroupsModule.GetMembershipData(AgentId); | 13356 | m_GroupsModule.GetMembershipData(AgentId); |
12684 | 13357 | ||
12685 | m_groupPowers.Clear(); | 13358 | m_groupPowers.Clear(); |
12686 | 13359 | ||
12687 | if (GroupMembership != null) | 13360 | if (GroupMembership != null) |
12688 | { | 13361 | { |
12689 | for (int i = 0; i < GroupMembership.Length; i++) | 13362 | for (int i = 0; i < GroupMembership.Length; i++) |
13363 | { | ||
13364 | m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers; | ||
13365 | } | ||
13366 | } | ||
13367 | |||
13368 | activeMembership = m_GroupsModule.GetActiveMembershipData(AgentId); | ||
13369 | if(activeMembership != null) | ||
12690 | { | 13370 | { |
12691 | m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers; | 13371 | if(!m_groupPowers.ContainsKey(activeMembership.GroupID)) |
13372 | activeMembership = null; | ||
13373 | else | ||
13374 | { | ||
13375 | m_activeGroupID = activeMembership.GroupID; | ||
13376 | m_activeGroupName = activeMembership.GroupName; | ||
13377 | m_activeGroupPowers = ActiveGroupPowers; | ||
13378 | } | ||
12692 | } | 13379 | } |
12693 | } | 13380 | } |
13381 | |||
13382 | if(activeMembership == null) | ||
13383 | { | ||
13384 | m_activeGroupID = UUID.Zero; | ||
13385 | m_activeGroupName = ""; | ||
13386 | m_activeGroupPowers = 0; | ||
13387 | } | ||
13388 | } | ||
13389 | } | ||
13390 | |||
13391 | public void UpdateGroupMembership(GroupMembershipData[] data) | ||
13392 | { | ||
13393 | lock(m_groupPowers) | ||
13394 | { | ||
13395 | m_groupPowers.Clear(); | ||
13396 | |||
13397 | if (data != null) | ||
13398 | { | ||
13399 | for (int i = 0; i < data.Length; i++) | ||
13400 | m_groupPowers[data[i].GroupID] = data[i].GroupPowers; | ||
13401 | } | ||
13402 | } | ||
13403 | } | ||
13404 | |||
13405 | public void GroupMembershipRemove(UUID GroupID) | ||
13406 | { | ||
13407 | lock(m_groupPowers) | ||
13408 | { | ||
13409 | if(m_groupPowers.ContainsKey(GroupID)) | ||
13410 | m_groupPowers.Remove(GroupID); | ||
13411 | } | ||
13412 | } | ||
13413 | |||
13414 | public void GroupMembershipAddReplace(UUID GroupID,ulong GroupPowers) | ||
13415 | { | ||
13416 | lock(m_groupPowers) | ||
13417 | { | ||
13418 | m_groupPowers[GroupID] = GroupPowers; | ||
12694 | } | 13419 | } |
12695 | } | 13420 | } |
12696 | 13421 | ||
@@ -12736,7 +13461,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12736 | // "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", | 13461 | // "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", |
12737 | // requestID, taskID, (SourceType)sourceType, Name); | 13462 | // requestID, taskID, (SourceType)sourceType, Name); |
12738 | 13463 | ||
13464 | |||
13465 | //Note, the bool returned from the below function is useless since it is always false. | ||
12739 | m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); | 13466 | m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); |
13467 | |||
12740 | } | 13468 | } |
12741 | 13469 | ||
12742 | /// <summary> | 13470 | /// <summary> |
@@ -12782,7 +13510,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12782 | SendAssetNotFound(req); | 13510 | SendAssetNotFound(req); |
12783 | return; | 13511 | return; |
12784 | } | 13512 | } |
12785 | |||
12786 | } | 13513 | } |
12787 | 13514 | ||
12788 | if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset) | 13515 | if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset) |
@@ -12819,7 +13546,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12819 | /// <returns></returns> | 13546 | /// <returns></returns> |
12820 | private static int CalculateNumPackets(byte[] data) | 13547 | private static int CalculateNumPackets(byte[] data) |
12821 | { | 13548 | { |
12822 | const uint m_maxPacketSize = 600; | 13549 | // const uint m_maxPacketSize = 600; |
13550 | uint m_maxPacketSize = MaxTransferBytesPerPacket; | ||
12823 | int numPackets = 1; | 13551 | int numPackets = 1; |
12824 | 13552 | ||
12825 | if (data == null) | 13553 | if (data == null) |
@@ -12858,11 +13586,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12858 | /// </summary> | 13586 | /// </summary> |
12859 | public bool Async { get; set; } | 13587 | public bool Async { get; set; } |
12860 | 13588 | ||
12861 | /// <summary> | ||
12862 | /// If async is true, should this packet be handled in the async engine or given directly to a threadpool | ||
12863 | /// thread? | ||
12864 | /// </summary> | ||
12865 | public bool InEngine { get; set; } | ||
12866 | } | 13589 | } |
12867 | 13590 | ||
12868 | public class AsyncPacketProcess | 13591 | public class AsyncPacketProcess |
@@ -12930,7 +13653,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12930 | // this is the username of the *owner* | 13653 | // this is the username of the *owner* |
12931 | dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName); | 13654 | dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName); |
12932 | dialog.Data.LastName = Util.StringToBytes256(ownerLastName); | 13655 | dialog.Data.LastName = Util.StringToBytes256(ownerLastName); |
12933 | dialog.Data.Message = Util.StringToBytes256(message); | 13656 | dialog.Data.Message = Util.StringToBytes(message,512); |
12934 | 13657 | ||
12935 | ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[1]; | 13658 | ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[1]; |
12936 | buttons[0] = new ScriptDialogPacket.ButtonsBlock(); | 13659 | buttons[0] = new ScriptDialogPacket.ButtonsBlock(); |
@@ -12949,7 +13672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12949 | if (p is ScenePresence) | 13672 | if (p is ScenePresence) |
12950 | { | 13673 | { |
12951 | // m_log.DebugFormat( | 13674 | // m_log.DebugFormat( |
12952 | // "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}", | 13675 | // "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}", |
12953 | // p.Name, Name, Scene.Name); | 13676 | // p.Name, Name, Scene.Name); |
12954 | 13677 | ||
12955 | // It turns out to get the agent to stop flying, you have to feed it stop flying velocities | 13678 | // It turns out to get the agent to stop flying, you have to feed it stop flying velocities |
@@ -12962,8 +13685,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12962 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = | 13685 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = |
12963 | CreateImprovedTerseBlock(p, false); | 13686 | CreateImprovedTerseBlock(p, false); |
12964 | 13687 | ||
12965 | const float TIME_DILATION = 1.0f; | 13688 | // const float TIME_DILATION = 1.0f; |
12966 | ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); | 13689 | ushort timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);; |
12967 | 13690 | ||
12968 | ImprovedTerseObjectUpdatePacket packet | 13691 | ImprovedTerseObjectUpdatePacket packet |
12969 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( | 13692 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( |
@@ -12986,7 +13709,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12986 | PlacesReplyData[] data) | 13709 | PlacesReplyData[] data) |
12987 | { | 13710 | { |
12988 | PlacesReplyPacket reply = null; | 13711 | PlacesReplyPacket reply = null; |
12989 | PlacesReplyPacket.QueryDataBlock[] dataBlocks = | 13712 | PlacesReplyPacket.QueryDataBlock[] dataBlocks = |
12990 | new PlacesReplyPacket.QueryDataBlock[0]; | 13713 | new PlacesReplyPacket.QueryDataBlock[0]; |
12991 | 13714 | ||
12992 | for (int i = 0 ; i < data.Length ; i++) | 13715 | for (int i = 0 ; i < data.Length ; i++) |
@@ -13164,7 +13887,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
13164 | foreach (InventoryItemBase item in items) | 13887 | foreach (InventoryItemBase item in items) |
13165 | { | 13888 | { |
13166 | OSDMap ItemDataMap = new OSDMap(); | 13889 | OSDMap ItemDataMap = new OSDMap(); |
13167 | 13890 | ||
13168 | ItemDataMap.Add("ItemID", OSD.FromUUID(item.ID)); | 13891 | ItemDataMap.Add("ItemID", OSD.FromUUID(item.ID)); |
13169 | ItemDataMap.Add("FolderID", OSD.FromUUID(item.Folder)); | 13892 | ItemDataMap.Add("FolderID", OSD.FromUUID(item.Folder)); |
13170 | 13893 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs index 41dd4d1..deefd40 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs | |||
@@ -82,7 +82,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
82 | 82 | ||
83 | if (pAssetCache != null) | 83 | if (pAssetCache != null) |
84 | m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f"); | 84 | m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f"); |
85 | 85 | ||
86 | if (m_missingImage == null) | 86 | if (m_missingImage == null) |
87 | m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client"); | 87 | m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client"); |
88 | 88 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 0394e54..439621a 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | |||
@@ -52,7 +52,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
52 | /// are waiting on ACKs for</param> | 52 | /// are waiting on ACKs for</param> |
53 | public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes); | 53 | public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes); |
54 | /// <summary> | 54 | /// <summary> |
55 | /// Fired when the queue for one or more packet categories is empty. This | 55 | /// Fired when the queue for one or more packet categories is empty. This |
56 | /// event can be hooked to put more data on the empty queues | 56 | /// event can be hooked to put more data on the empty queues |
57 | /// </summary> | 57 | /// </summary> |
58 | /// <param name="category">Categories of the packet queues that are empty</param> | 58 | /// <param name="category">Categories of the packet queues that are empty</param> |
@@ -86,8 +86,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
86 | /// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes. | 86 | /// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes. |
87 | /// </summary> | 87 | /// </summary> |
88 | /// <remarks>Any level above 0 will turn on logging.</remarks> | 88 | /// <remarks>Any level above 0 will turn on logging.</remarks> |
89 | public int ThrottleDebugLevel | 89 | public int ThrottleDebugLevel |
90 | { | 90 | { |
91 | get | 91 | get |
92 | { | 92 | { |
93 | return m_throttleDebugLevel; | 93 | return m_throttleDebugLevel; |
@@ -96,9 +96,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
96 | set | 96 | set |
97 | { | 97 | { |
98 | m_throttleDebugLevel = value; | 98 | m_throttleDebugLevel = value; |
99 | /* | ||
99 | m_throttleClient.DebugLevel = m_throttleDebugLevel; | 100 | m_throttleClient.DebugLevel = m_throttleDebugLevel; |
100 | foreach (TokenBucket tb in m_throttleCategories) | 101 | foreach (TokenBucket tb in m_throttleCategories) |
101 | tb.DebugLevel = m_throttleDebugLevel; | 102 | tb.DebugLevel = m_throttleDebugLevel; |
103 | */ | ||
102 | } | 104 | } |
103 | } | 105 | } |
104 | private int m_throttleDebugLevel; | 106 | private int m_throttleDebugLevel; |
@@ -118,18 +120,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
118 | /// <summary>Circuit code that this client is connected on</summary> | 120 | /// <summary>Circuit code that this client is connected on</summary> |
119 | public readonly uint CircuitCode; | 121 | public readonly uint CircuitCode; |
120 | /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary> | 122 | /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary> |
121 | public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); | 123 | public IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); |
122 | |||
123 | /// <summary> | ||
124 | /// If true then we take action in response to unacked reliably sent packets such as resending the packet. | ||
125 | /// </summary> | ||
126 | public bool ProcessUnackedSends { get; set; } | ||
127 | 124 | ||
128 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> | 125 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> |
129 | public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); | 126 | public UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); |
130 | 127 | ||
131 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> | 128 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> |
132 | public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); | 129 | public DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>(); |
133 | 130 | ||
134 | /// <summary>Current packet sequence number</summary> | 131 | /// <summary>Current packet sequence number</summary> |
135 | public int CurrentSequence; | 132 | public int CurrentSequence; |
@@ -160,19 +157,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
160 | /// <summary>Number of packets sent to this client</summary> | 157 | /// <summary>Number of packets sent to this client</summary> |
161 | public int PacketsSent; | 158 | public int PacketsSent; |
162 | /// <summary>Number of packets resent to this client</summary> | 159 | /// <summary>Number of packets resent to this client</summary> |
163 | public int PacketsResent; | 160 | public int PacketsResent; |
164 | /// <summary>Total byte count of unacked packets sent to this client</summary> | 161 | /// <summary>Total byte count of unacked packets sent to this client</summary> |
165 | public int UnackedBytes; | 162 | public int UnackedBytes; |
166 | 163 | ||
164 | private int m_packetsUnAckReported; | ||
167 | /// <summary>Total number of received packets that we have reported to the OnPacketStats event(s)</summary> | 165 | /// <summary>Total number of received packets that we have reported to the OnPacketStats event(s)</summary> |
168 | private int m_packetsReceivedReported; | 166 | private int m_packetsReceivedReported; |
169 | /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary> | 167 | /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary> |
170 | private int m_packetsSentReported; | 168 | private int m_packetsSentReported; |
171 | /// <summary>Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired</summary> | 169 | /// <summary>Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired</summary> |
172 | private int m_nextOnQueueEmpty = 1; | 170 | private double m_nextOnQueueEmpty = 0; |
173 | 171 | ||
174 | /// <summary>Throttle bucket for this agent's connection</summary> | 172 | /// <summary>Throttle bucket for this agent's connection</summary> |
175 | private readonly AdaptiveTokenBucket m_throttleClient; | 173 | private AdaptiveTokenBucket m_throttleClient; |
176 | public AdaptiveTokenBucket FlowThrottle | 174 | public AdaptiveTokenBucket FlowThrottle |
177 | { | 175 | { |
178 | get { return m_throttleClient; } | 176 | get { return m_throttleClient; } |
@@ -181,10 +179,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
181 | /// <summary>Throttle buckets for each packet category</summary> | 179 | /// <summary>Throttle buckets for each packet category</summary> |
182 | private readonly TokenBucket[] m_throttleCategories; | 180 | private readonly TokenBucket[] m_throttleCategories; |
183 | /// <summary>Outgoing queues for throttled packets</summary> | 181 | /// <summary>Outgoing queues for throttled packets</summary> |
184 | private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; | 182 | private DoubleLocklessQueue<OutgoingPacket>[] m_packetOutboxes = new DoubleLocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; |
185 | /// <summary>A container that can hold one packet for each outbox, used to store | 183 | /// <summary>A container that can hold one packet for each outbox, used to store |
186 | /// dequeued packets that are being held for throttling</summary> | 184 | /// dequeued packets that are being held for throttling</summary> |
187 | private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; | 185 | private OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; |
188 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> | 186 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> |
189 | private readonly LLUDPServer m_udpServer; | 187 | private readonly LLUDPServer m_udpServer; |
190 | 188 | ||
@@ -193,13 +191,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
193 | 191 | ||
194 | private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC | 192 | private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC |
195 | private int m_maxRTO = 60000; | 193 | private int m_maxRTO = 60000; |
194 | public bool m_deliverPackets = true; | ||
195 | |||
196 | private float m_burstTime; | ||
197 | |||
198 | public int m_lastStartpingTimeMS; | ||
199 | public int m_pingMS; | ||
200 | |||
201 | public int PingTimeMS | ||
202 | { | ||
203 | get | ||
204 | { | ||
205 | if (m_pingMS < 10) | ||
206 | return 10; | ||
207 | if(m_pingMS > 2000) | ||
208 | return 2000; | ||
209 | return m_pingMS; | ||
210 | } | ||
211 | } | ||
196 | 212 | ||
197 | /// <summary> | 213 | /// <summary> |
198 | /// This is the percentage of the udp texture queue to add to the task queue since | 214 | /// This is the percentage of the udp texture queue to add to the task queue since |
199 | /// textures are now generally handled through http. | 215 | /// textures are now generally handled through http. |
200 | /// </summary> | 216 | /// </summary> |
201 | private double m_cannibalrate = 0.0; | 217 | private double m_cannibalrate = 0.0; |
202 | 218 | ||
203 | private ClientInfo m_info = new ClientInfo(); | 219 | private ClientInfo m_info = new ClientInfo(); |
204 | 220 | ||
205 | /// <summary> | 221 | /// <summary> |
@@ -232,31 +248,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
232 | if (maxRTO != 0) | 248 | if (maxRTO != 0) |
233 | m_maxRTO = maxRTO; | 249 | m_maxRTO = maxRTO; |
234 | 250 | ||
235 | ProcessUnackedSends = true; | 251 | m_burstTime = rates.BrustTime; |
252 | float m_burst = rates.ClientMaxRate * m_burstTime; | ||
236 | 253 | ||
237 | // Create a token bucket throttle for this client that has the scene token bucket as a parent | 254 | // Create a token bucket throttle for this client that has the scene token bucket as a parent |
238 | m_throttleClient | 255 | m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.ClientMaxRate, m_burst, rates.AdaptiveThrottlesEnabled); |
239 | = new AdaptiveTokenBucket( | ||
240 | string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name), | ||
241 | parentThrottle, 0, rates.Total, rates.MinimumAdaptiveThrottleRate, rates.AdaptiveThrottlesEnabled); | ||
242 | 256 | ||
243 | // Create an array of token buckets for this clients different throttle categories | 257 | // Create an array of token buckets for this clients different throttle categories |
244 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 258 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
245 | 259 | ||
246 | m_cannibalrate = rates.CannibalizeTextureRate; | 260 | m_cannibalrate = rates.CannibalizeTextureRate; |
247 | 261 | ||
262 | m_burst = rates.Total * rates.BrustTime; | ||
263 | |||
248 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 264 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
249 | { | 265 | { |
250 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | 266 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; |
251 | 267 | ||
252 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens | 268 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens |
253 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); | 269 | m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); |
254 | |||
255 | // Initialize the token buckets that control the throttling for each category | 270 | // Initialize the token buckets that control the throttling for each category |
256 | m_throttleCategories[i] | 271 | m_throttleCategories[i] = new TokenBucket(m_throttleClient, rates.GetRate(type), m_burst); |
257 | = new TokenBucket( | ||
258 | string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name), | ||
259 | m_throttleClient, rates.GetRate(type), 0); | ||
260 | } | 272 | } |
261 | 273 | ||
262 | // Default the retransmission timeout to one second | 274 | // Default the retransmission timeout to one second |
@@ -264,6 +276,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
264 | 276 | ||
265 | // Initialize this to a sane value to prevent early disconnects | 277 | // Initialize this to a sane value to prevent early disconnects |
266 | TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; | 278 | TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; |
279 | m_pingMS = (int)(3.0 * server.TickCountResolution); // so filter doesnt start at 0; | ||
267 | } | 280 | } |
268 | 281 | ||
269 | /// <summary> | 282 | /// <summary> |
@@ -280,9 +293,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
280 | 293 | ||
281 | // pull the throttle out of the scene throttle | 294 | // pull the throttle out of the scene throttle |
282 | m_throttleClient.Parent.UnregisterRequest(m_throttleClient); | 295 | m_throttleClient.Parent.UnregisterRequest(m_throttleClient); |
283 | OnPacketStats = null; | 296 | PendingAcks.Clear(); |
284 | OnQueueEmpty = null; | 297 | NeedAcks.Clear(); |
285 | } | 298 | } |
286 | 299 | ||
287 | /// <summary> | 300 | /// <summary> |
288 | /// Gets information about this client connection | 301 | /// Gets information about this client connection |
@@ -302,9 +315,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
302 | m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 315 | m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
303 | m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 316 | m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
304 | m_info.totalThrottle = (int)m_throttleClient.DripRate; | 317 | m_info.totalThrottle = (int)m_throttleClient.DripRate; |
305 | m_info.targetThrottle = (int)m_throttleClient.TargetDripRate; | ||
306 | m_info.maxThrottle = (int)m_throttleClient.MaxDripRate; | ||
307 | |||
308 | return m_info; | 318 | return m_info; |
309 | } | 319 | } |
310 | 320 | ||
@@ -341,8 +351,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
341 | /// <param name="throttleType"></param> | 351 | /// <param name="throttleType"></param> |
342 | public int GetPacketsQueuedCount(ThrottleOutPacketType throttleType) | 352 | public int GetPacketsQueuedCount(ThrottleOutPacketType throttleType) |
343 | { | 353 | { |
344 | if ((int)throttleType > 0) | 354 | int icat = (int)throttleType; |
345 | return m_packetOutboxes[(int)throttleType].Count; | 355 | if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT) |
356 | return m_packetOutboxes[icat].Count; | ||
346 | else | 357 | else |
347 | return 0; | 358 | return 0; |
348 | } | 359 | } |
@@ -359,7 +370,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
359 | return string.Format( | 370 | return string.Format( |
360 | "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}", | 371 | "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}", |
361 | Util.EnvironmentTickCountSubtract(TickLastPacketReceived), | 372 | Util.EnvironmentTickCountSubtract(TickLastPacketReceived), |
362 | PacketsReceived, | 373 | PacketsReceived, |
363 | PacketsSent, | 374 | PacketsSent, |
364 | PacketsResent, | 375 | PacketsResent, |
365 | UnackedBytes, | 376 | UnackedBytes, |
@@ -379,16 +390,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
379 | { | 390 | { |
380 | int newPacketsReceived = PacketsReceived - m_packetsReceivedReported; | 391 | int newPacketsReceived = PacketsReceived - m_packetsReceivedReported; |
381 | int newPacketsSent = PacketsSent - m_packetsSentReported; | 392 | int newPacketsSent = PacketsSent - m_packetsSentReported; |
382 | 393 | int newPacketUnAck = UnackedBytes - m_packetsUnAckReported; | |
383 | callback(newPacketsReceived, newPacketsSent, UnackedBytes); | 394 | callback(newPacketsReceived, newPacketsSent, UnackedBytes); |
384 | 395 | ||
385 | m_packetsReceivedReported += newPacketsReceived; | 396 | m_packetsReceivedReported += newPacketsReceived; |
386 | m_packetsSentReported += newPacketsSent; | 397 | m_packetsSentReported += newPacketsSent; |
398 | m_packetsUnAckReported += newPacketUnAck; | ||
387 | } | 399 | } |
388 | } | 400 | } |
389 | 401 | ||
390 | public void SetThrottles(byte[] throttleData) | 402 | public void SetThrottles(byte[] throttleData) |
391 | { | 403 | { |
404 | SetThrottles(throttleData, 1.0f); | ||
405 | } | ||
406 | |||
407 | public void SetThrottles(byte[] throttleData, float factor) | ||
408 | { | ||
392 | byte[] adjData; | 409 | byte[] adjData; |
393 | int pos = 0; | 410 | int pos = 0; |
394 | 411 | ||
@@ -408,24 +425,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
408 | } | 425 | } |
409 | 426 | ||
410 | // 0.125f converts from bits to bytes | 427 | // 0.125f converts from bits to bytes |
411 | int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 428 | float scale = 0.125f * factor; |
412 | int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 429 | int resend = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; |
413 | int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 430 | int land = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; |
414 | int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 431 | int wind = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; |
415 | int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 432 | int cloud = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; |
416 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 433 | int task = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; |
417 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | 434 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4; |
435 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * scale); | ||
436 | |||
418 | 437 | ||
419 | if (ThrottleDebugLevel > 0) | ||
420 | { | ||
421 | long total = resend + land + wind + cloud + task + texture + asset; | ||
422 | m_log.DebugFormat( | ||
423 | "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}", | ||
424 | AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total); | ||
425 | } | ||
426 | 438 | ||
427 | // Make sure none of the throttles are set below our packet MTU, | 439 | // Make sure none of the throttles are set below our packet MTU, |
428 | // otherwise a throttle could become permanently clogged | 440 | // otherwise a throttle could become permanently clogged |
441 | |||
442 | /* now using floats | ||
429 | resend = Math.Max(resend, LLUDPServer.MTU); | 443 | resend = Math.Max(resend, LLUDPServer.MTU); |
430 | land = Math.Max(land, LLUDPServer.MTU); | 444 | land = Math.Max(land, LLUDPServer.MTU); |
431 | wind = Math.Max(wind, LLUDPServer.MTU); | 445 | wind = Math.Max(wind, LLUDPServer.MTU); |
@@ -433,52 +447,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
433 | task = Math.Max(task, LLUDPServer.MTU); | 447 | task = Math.Max(task, LLUDPServer.MTU); |
434 | texture = Math.Max(texture, LLUDPServer.MTU); | 448 | texture = Math.Max(texture, LLUDPServer.MTU); |
435 | asset = Math.Max(asset, LLUDPServer.MTU); | 449 | asset = Math.Max(asset, LLUDPServer.MTU); |
450 | */ | ||
436 | 451 | ||
437 | // Since most textures are now delivered through http, make it possible | 452 | // Since most textures are now delivered through http, make it possible |
438 | // to cannibalize some of the bw from the texture throttle to use for | 453 | // to cannibalize some of the bw from the texture throttle to use for |
439 | // the task queue (e.g. object updates) | 454 | // the task queue (e.g. object updates) |
440 | task = task + (int)(m_cannibalrate * texture); | 455 | task = task + (int)(m_cannibalrate * texture); |
441 | texture = (int)((1 - m_cannibalrate) * texture); | 456 | texture = (int)((1 - m_cannibalrate) * texture); |
442 | 457 | ||
443 | //int total = resend + land + wind + cloud + task + texture + asset; | 458 | int total = resend + land + wind + cloud + task + texture + asset; |
459 | |||
460 | float m_burst = total * m_burstTime; | ||
444 | 461 | ||
445 | if (ThrottleDebugLevel > 0) | 462 | if (ThrottleDebugLevel > 0) |
446 | { | 463 | { |
447 | long total = resend + land + wind + cloud + task + texture + asset; | ||
448 | m_log.DebugFormat( | 464 | m_log.DebugFormat( |
449 | "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}", | 465 | "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}", |
450 | AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total); | 466 | AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total); |
451 | } | 467 | } |
452 | 468 | ||
453 | // Update the token buckets with new throttle values | ||
454 | if (m_throttleClient.AdaptiveEnabled) | ||
455 | { | ||
456 | long total = resend + land + wind + cloud + task + texture + asset; | ||
457 | m_throttleClient.TargetDripRate = total; | ||
458 | } | ||
459 | |||
460 | TokenBucket bucket; | 469 | TokenBucket bucket; |
461 | 470 | ||
462 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; | 471 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; |
463 | bucket.RequestedDripRate = resend; | 472 | bucket.RequestedDripRate = resend; |
473 | bucket.RequestedBurst = m_burst; | ||
464 | 474 | ||
465 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; | 475 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; |
466 | bucket.RequestedDripRate = land; | 476 | bucket.RequestedDripRate = land; |
477 | bucket.RequestedBurst = m_burst; | ||
467 | 478 | ||
468 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; | 479 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; |
469 | bucket.RequestedDripRate = wind; | 480 | bucket.RequestedDripRate = wind; |
481 | bucket.RequestedBurst = m_burst; | ||
470 | 482 | ||
471 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; | 483 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; |
472 | bucket.RequestedDripRate = cloud; | 484 | bucket.RequestedDripRate = cloud; |
485 | bucket.RequestedBurst = m_burst; | ||
473 | 486 | ||
474 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; | 487 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; |
475 | bucket.RequestedDripRate = asset; | 488 | bucket.RequestedDripRate = asset; |
489 | bucket.RequestedBurst = m_burst; | ||
476 | 490 | ||
477 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; | 491 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; |
478 | bucket.RequestedDripRate = task; | 492 | bucket.RequestedDripRate = task; |
493 | bucket.RequestedBurst = m_burst; | ||
479 | 494 | ||
480 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; | 495 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; |
481 | bucket.RequestedDripRate = texture; | 496 | bucket.RequestedDripRate = texture; |
497 | bucket.RequestedBurst = m_burst; | ||
482 | 498 | ||
483 | // Reset the packed throttles cached data | 499 | // Reset the packed throttles cached data |
484 | m_packedThrottles = null; | 500 | m_packedThrottles = null; |
@@ -496,25 +512,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
496 | int i = 0; | 512 | int i = 0; |
497 | 513 | ||
498 | // multiply by 8 to convert bytes back to bits | 514 | // multiply by 8 to convert bytes back to bits |
499 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier; | 515 | multiplier *= 8; |
516 | |||
517 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * multiplier; | ||
500 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | 518 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; |
501 | 519 | ||
502 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier; | 520 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * multiplier; |
503 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | 521 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; |
504 | 522 | ||
505 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier; | 523 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * multiplier; |
506 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | 524 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; |
507 | 525 | ||
508 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier; | 526 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * multiplier; |
509 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | 527 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; |
510 | 528 | ||
511 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier; | 529 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * multiplier; |
512 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | 530 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; |
513 | 531 | ||
514 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier; | 532 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * multiplier; |
515 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | 533 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; |
516 | 534 | ||
517 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier; | 535 | rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * multiplier; |
518 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; | 536 | Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; |
519 | 537 | ||
520 | m_packedThrottles = data; | 538 | m_packedThrottles = data; |
@@ -523,43 +541,65 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
523 | return data; | 541 | return data; |
524 | } | 542 | } |
525 | 543 | ||
544 | public int GetCatBytesCanSend(ThrottleOutPacketType cat, int timeMS) | ||
545 | { | ||
546 | int icat = (int)cat; | ||
547 | if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT) | ||
548 | { | ||
549 | TokenBucket bucket = m_throttleCategories[icat]; | ||
550 | return bucket.GetCatBytesCanSend(timeMS); | ||
551 | } | ||
552 | else | ||
553 | return 0; | ||
554 | } | ||
555 | |||
526 | /// <summary> | 556 | /// <summary> |
527 | /// Queue an outgoing packet if appropriate. | 557 | /// Queue an outgoing packet if appropriate. |
528 | /// </summary> | 558 | /// </summary> |
529 | /// <param name="packet"></param> | 559 | /// <param name="packet"></param> |
530 | /// <param name="forceQueue">Always queue the packet if at all possible.</param> | 560 | /// <param name="forceQueue">Always queue the packet if at all possible.</param> |
531 | /// <returns> | 561 | /// <returns> |
532 | /// true if the packet has been queued, | 562 | /// true if the packet has been queued, |
533 | /// false if the packet has not been queued and should be sent immediately. | 563 | /// false if the packet has not been queued and should be sent immediately. |
534 | /// </returns> | 564 | /// </returns> |
535 | public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) | 565 | public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) |
536 | { | 566 | { |
567 | return EnqueueOutgoing(packet, forceQueue, false); | ||
568 | } | ||
569 | |||
570 | public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority) | ||
571 | { | ||
537 | int category = (int)packet.Category; | 572 | int category = (int)packet.Category; |
538 | 573 | ||
539 | if (category >= 0 && category < m_packetOutboxes.Length) | 574 | if (category >= 0 && category < m_packetOutboxes.Length) |
540 | { | 575 | { |
541 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; | 576 | DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; |
577 | |||
578 | if (m_deliverPackets == false) | ||
579 | { | ||
580 | queue.Enqueue(packet, highPriority); | ||
581 | return true; | ||
582 | } | ||
583 | |||
542 | TokenBucket bucket = m_throttleCategories[category]; | 584 | TokenBucket bucket = m_throttleCategories[category]; |
543 | 585 | ||
544 | // Don't send this packet if there is already a packet waiting in the queue | 586 | // Don't send this packet if queue is not empty |
545 | // even if we have the tokens to send it, tokens should go to the already | 587 | if (queue.Count > 0 || m_nextPackets[category] != null) |
546 | // queued packets | ||
547 | if (queue.Count > 0) | ||
548 | { | 588 | { |
549 | queue.Enqueue(packet); | 589 | queue.Enqueue(packet, highPriority); |
550 | return true; | 590 | return true; |
551 | } | 591 | } |
552 | 592 | ||
553 | 593 | if (!forceQueue && bucket.CheckTokens(packet.Buffer.DataLength)) | |
554 | if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) | ||
555 | { | 594 | { |
556 | // Enough tokens were removed from the bucket, the packet will not be queued | 595 | // enough tokens so it can be sent imediatly by caller |
596 | bucket.RemoveTokens(packet.Buffer.DataLength); | ||
557 | return false; | 597 | return false; |
558 | } | 598 | } |
559 | else | 599 | else |
560 | { | 600 | { |
561 | // Force queue specified or not enough tokens in the bucket, queue this packet | 601 | // Force queue specified or not enough tokens in the bucket, queue this packet |
562 | queue.Enqueue(packet); | 602 | queue.Enqueue(packet, highPriority); |
563 | return true; | 603 | return true; |
564 | } | 604 | } |
565 | } | 605 | } |
@@ -568,28 +608,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
568 | // We don't have a token bucket for this category, so it will not be queued | 608 | // We don't have a token bucket for this category, so it will not be queued |
569 | return false; | 609 | return false; |
570 | } | 610 | } |
611 | |||
571 | } | 612 | } |
572 | 613 | ||
573 | /// <summary> | 614 | /// <summary> |
574 | /// Loops through all of the packet queues for this client and tries to send | 615 | /// Loops through all of the packet queues for this client and tries to send |
575 | /// an outgoing packet from each, obeying the throttling bucket limits | 616 | /// an outgoing packet from each, obeying the throttling bucket limits |
576 | /// </summary> | 617 | /// </summary> |
577 | /// | 618 | /// |
578 | /// <remarks> | 619 | /// <remarks> |
579 | /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower | 620 | /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower |
580 | /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have | 621 | /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have |
581 | /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the | 622 | /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the |
582 | /// wind queue). | 623 | /// wind queue). |
583 | /// | 624 | /// |
584 | /// This function is only called from a synchronous loop in the | 625 | /// This function is only called from a synchronous loop in the |
585 | /// UDPServer so we don't need to bother making this thread safe | 626 | /// UDPServer so we don't need to bother making this thread safe |
586 | /// </remarks> | 627 | /// </remarks> |
587 | /// | 628 | /// |
588 | /// <returns>True if any packets were sent, otherwise false</returns> | 629 | /// <returns>True if any packets were sent, otherwise false</returns> |
589 | public bool DequeueOutgoing() | 630 | public bool DequeueOutgoing() |
590 | { | 631 | { |
591 | OutgoingPacket packet; | 632 | // if (m_deliverPackets == false) return false; |
592 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; | 633 | |
634 | OutgoingPacket packet = null; | ||
635 | DoubleLocklessQueue<OutgoingPacket> queue; | ||
593 | TokenBucket bucket; | 636 | TokenBucket bucket; |
594 | bool packetSent = false; | 637 | bool packetSent = false; |
595 | ThrottleOutPacketTypeFlags emptyCategories = 0; | 638 | ThrottleOutPacketTypeFlags emptyCategories = 0; |
@@ -613,6 +656,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
613 | m_udpServer.SendPacketFinal(nextPacket); | 656 | m_udpServer.SendPacketFinal(nextPacket); |
614 | m_nextPackets[i] = null; | 657 | m_nextPackets[i] = null; |
615 | packetSent = true; | 658 | packetSent = true; |
659 | |||
660 | if (m_packetOutboxes[i].Count < 5) | ||
661 | emptyCategories |= CategoryToFlag(i); | ||
616 | } | 662 | } |
617 | } | 663 | } |
618 | else | 664 | else |
@@ -620,32 +666,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
620 | // No dequeued packet waiting to be sent, try to pull one off | 666 | // No dequeued packet waiting to be sent, try to pull one off |
621 | // this queue | 667 | // this queue |
622 | queue = m_packetOutboxes[i]; | 668 | queue = m_packetOutboxes[i]; |
623 | if (queue.Dequeue(out packet)) | 669 | if (queue != null) |
624 | { | 670 | { |
625 | // A packet was pulled off the queue. See if we have | 671 | bool success = false; |
626 | // enough tokens in the bucket to send it out | 672 | try |
627 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) | ||
628 | { | 673 | { |
629 | // Send the packet | 674 | success = queue.Dequeue(out packet); |
630 | m_udpServer.SendPacketFinal(packet); | ||
631 | packetSent = true; | ||
632 | } | 675 | } |
633 | else | 676 | catch |
634 | { | 677 | { |
635 | // Save the dequeued packet for the next iteration | 678 | m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); |
636 | m_nextPackets[i] = packet; | ||
637 | } | 679 | } |
680 | if (success) | ||
681 | { | ||
682 | // A packet was pulled off the queue. See if we have | ||
683 | // enough tokens in the bucket to send it out | ||
684 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) | ||
685 | { | ||
686 | // Send the packet | ||
687 | m_udpServer.SendPacketFinal(packet); | ||
688 | packetSent = true; | ||
689 | |||
690 | if (queue.Count < 5) | ||
691 | emptyCategories |= CategoryToFlag(i); | ||
692 | } | ||
693 | else | ||
694 | { | ||
695 | // Save the dequeued packet for the next iteration | ||
696 | m_nextPackets[i] = packet; | ||
697 | } | ||
638 | 698 | ||
639 | // If the queue is empty after this dequeue, fire the queue | 699 | } |
640 | // empty callback now so it has a chance to fill before we | 700 | else |
641 | // get back here | 701 | { |
642 | if (queue.Count == 0) | 702 | // No packets in this queue. Fire the queue empty callback |
703 | // if it has not been called recently | ||
643 | emptyCategories |= CategoryToFlag(i); | 704 | emptyCategories |= CategoryToFlag(i); |
705 | } | ||
644 | } | 706 | } |
645 | else | 707 | else |
646 | { | 708 | { |
647 | // No packets in this queue. Fire the queue empty callback | 709 | m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); |
648 | // if it has not been called recently | ||
649 | emptyCategories |= CategoryToFlag(i); | 710 | emptyCategories |= CategoryToFlag(i); |
650 | } | 711 | } |
651 | } | 712 | } |
@@ -712,6 +773,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
712 | RTO = Math.Min(RTO * 2, m_maxRTO); | 773 | RTO = Math.Min(RTO * 2, m_maxRTO); |
713 | } | 774 | } |
714 | 775 | ||
776 | const double MIN_CALLBACK_MS = 20.0; | ||
777 | private bool m_isQueueEmptyRunning; | ||
778 | |||
715 | /// <summary> | 779 | /// <summary> |
716 | /// Does an early check to see if this queue empty callback is already | 780 | /// Does an early check to see if this queue empty callback is already |
717 | /// running, then asynchronously firing the event | 781 | /// running, then asynchronously firing the event |
@@ -719,44 +783,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
719 | /// <param name="categories">Throttle categories to fire the callback for</param> | 783 | /// <param name="categories">Throttle categories to fire the callback for</param> |
720 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) | 784 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) |
721 | { | 785 | { |
722 | // if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | 786 | if (!m_isQueueEmptyRunning) |
723 | if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | ||
724 | { | 787 | { |
725 | m_isQueueEmptyRunning = true; | 788 | if (!HasUpdates(categories)) |
789 | return; | ||
726 | 790 | ||
727 | int start = Environment.TickCount & Int32.MaxValue; | 791 | double start = Util.GetTimeStampMS(); |
728 | const int MIN_CALLBACK_MS = 30; | 792 | if (start < m_nextOnQueueEmpty) |
793 | return; | ||
729 | 794 | ||
795 | m_isQueueEmptyRunning = true; | ||
730 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | 796 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; |
731 | if (m_nextOnQueueEmpty == 0) | ||
732 | m_nextOnQueueEmpty = 1; | ||
733 | 797 | ||
734 | // Use a value of 0 to signal that FireQueueEmpty is running | 798 | // Asynchronously run the callback |
735 | // m_nextOnQueueEmpty = 0; | 799 | if (m_udpServer.OqrEngine.IsRunning) |
736 | 800 | m_udpServer.OqrEngine.QueueJob(AgentID.ToString(), () => FireQueueEmpty(categories)); | |
737 | m_categories = categories; | ||
738 | |||
739 | if (HasUpdates(m_categories)) | ||
740 | { | ||
741 | if (!m_udpServer.OqrEngine.IsRunning) | ||
742 | { | ||
743 | // Asynchronously run the callback | ||
744 | Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty"); | ||
745 | } | ||
746 | else | ||
747 | { | ||
748 | m_udpServer.OqrEngine.QueueJob(AgentID.ToString(), () => FireQueueEmpty(categories)); | ||
749 | } | ||
750 | } | ||
751 | else | 801 | else |
752 | { | 802 | Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty"); |
753 | m_isQueueEmptyRunning = false; | ||
754 | } | ||
755 | } | 803 | } |
756 | } | 804 | } |
757 | 805 | ||
758 | private bool m_isQueueEmptyRunning; | 806 | |
759 | private ThrottleOutPacketTypeFlags m_categories = 0; | ||
760 | 807 | ||
761 | /// <summary> | 808 | /// <summary> |
762 | /// Fires the OnQueueEmpty callback and sets the minimum time that it | 809 | /// Fires the OnQueueEmpty callback and sets the minimum time that it |
@@ -767,33 +814,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
767 | /// signature</param> | 814 | /// signature</param> |
768 | public void FireQueueEmpty(object o) | 815 | public void FireQueueEmpty(object o) |
769 | { | 816 | { |
770 | // m_log.DebugFormat("[LLUDPCLIENT]: FireQueueEmpty for {0} in {1}", AgentID, m_udpServer.Scene.Name); | 817 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; |
771 | 818 | QueueEmpty callback = OnQueueEmpty; | |
772 | // int start = Environment.TickCount & Int32.MaxValue; | ||
773 | // const int MIN_CALLBACK_MS = 30; | ||
774 | 819 | ||
775 | // if (m_udpServer.IsRunningOutbound) | 820 | if (callback != null) |
776 | // { | 821 | { |
777 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | 822 | // if (m_udpServer.IsRunningOutbound) |
778 | QueueEmpty callback = OnQueueEmpty; | 823 | // { |
779 | 824 | try { callback(categories); } | |
780 | if (callback != null) | 825 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } |
781 | { | 826 | // } |
782 | // if (m_udpServer.IsRunningOutbound) | 827 | } |
783 | // { | ||
784 | try { callback(categories); } | ||
785 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } | ||
786 | // } | ||
787 | } | ||
788 | // } | ||
789 | 828 | ||
790 | // m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | 829 | m_isQueueEmptyRunning = false; |
791 | // if (m_nextOnQueueEmpty == 0) | 830 | } |
792 | // m_nextOnQueueEmpty = 1; | ||
793 | 831 | ||
794 | // } | 832 | internal void ForceThrottleSetting(int throttle, int setting) |
833 | { | ||
834 | if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT) | ||
835 | m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU); | ||
836 | } | ||
795 | 837 | ||
796 | m_isQueueEmptyRunning = false; | 838 | internal int GetThrottleSetting(int throttle) |
839 | { | ||
840 | if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT) | ||
841 | return (int)m_throttleCategories[throttle].RequestedDripRate; | ||
842 | else | ||
843 | return 0; | ||
797 | } | 844 | } |
798 | 845 | ||
799 | /// <summary> | 846 | /// <summary> |
@@ -839,4 +886,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
839 | } | 886 | } |
840 | } | 887 | } |
841 | } | 888 | } |
889 | |||
890 | public class DoubleLocklessQueue<T> : OpenSim.Framework.LocklessQueue<T> | ||
891 | { | ||
892 | OpenSim.Framework.LocklessQueue<T> highQueue = new OpenSim.Framework.LocklessQueue<T>(); | ||
893 | |||
894 | public override int Count | ||
895 | { | ||
896 | get | ||
897 | { | ||
898 | return base.Count + highQueue.Count; | ||
899 | } | ||
900 | } | ||
901 | |||
902 | public override bool Dequeue(out T item) | ||
903 | { | ||
904 | if (highQueue.Dequeue(out item)) | ||
905 | return true; | ||
906 | |||
907 | return base.Dequeue(out item); | ||
908 | } | ||
909 | |||
910 | public void Enqueue(T item, bool highPriority) | ||
911 | { | ||
912 | if (highPriority) | ||
913 | highQueue.Enqueue(item); | ||
914 | else | ||
915 | Enqueue(item); | ||
916 | } | ||
917 | } | ||
842 | } | 918 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 4528714..69239b1 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -32,6 +32,8 @@ using System.IO; | |||
32 | using System.Net; | 32 | using System.Net; |
33 | using System.Net.Sockets; | 33 | using System.Net.Sockets; |
34 | using System.Reflection; | 34 | using System.Reflection; |
35 | using System.Text; | ||
36 | using System.Text.RegularExpressions; | ||
35 | using System.Threading; | 37 | using System.Threading; |
36 | using log4net; | 38 | using log4net; |
37 | using Nini.Config; | 39 | using Nini.Config; |
@@ -51,60 +53,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
51 | /// A shim around LLUDPServer that implements the IClientNetworkServer interface | 53 | /// A shim around LLUDPServer that implements the IClientNetworkServer interface |
52 | /// </summary> | 54 | /// </summary> |
53 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LLUDPServerShim")] | 55 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LLUDPServerShim")] |
54 | public sealed class LLUDPServerShim : INonSharedRegionModule | 56 | public class LLUDPServerShim : INonSharedRegionModule |
55 | { | 57 | { |
56 | private bool m_Enabled = true; | 58 | protected IConfigSource m_Config; |
57 | private IConfigSource m_Config; | 59 | protected LLUDPServer m_udpServer; |
58 | LLUDPServer m_udpServer; | ||
59 | 60 | ||
60 | #region INonSharedRegionModule | 61 | #region INonSharedRegionModule |
61 | public string Name | 62 | public virtual string Name |
62 | { | 63 | { |
63 | get { return "LLUDPServerShim"; } | 64 | get { return "LLUDPServerShim"; } |
64 | } | 65 | } |
65 | 66 | ||
66 | public Type ReplaceableInterface | 67 | public virtual Type ReplaceableInterface |
67 | { | 68 | { |
68 | get { return null; } | 69 | get { return null; } |
69 | } | 70 | } |
70 | 71 | ||
71 | public void Initialise(IConfigSource source) | 72 | public virtual void Initialise(IConfigSource source) |
72 | { | 73 | { |
73 | m_Config = source; | 74 | m_Config = source; |
74 | } | 75 | } |
75 | 76 | ||
76 | public void Close() | 77 | public virtual void Close() |
77 | { | 78 | { |
78 | } | 79 | } |
79 | 80 | ||
80 | public void AddRegion(Scene scene) | 81 | public virtual void AddRegion(Scene scene) |
81 | { | 82 | { |
82 | uint port = (uint)scene.RegionInfo.InternalEndPoint.Port; | 83 | uint port = (uint)scene.RegionInfo.InternalEndPoint.Port; |
83 | 84 | ||
84 | IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address; | 85 | IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address; |
85 | Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, scene.RegionInfo.m_allow_alternate_ports, m_Config, scene.AuthenticateHandler); | 86 | Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, m_Config, scene.AuthenticateHandler); |
86 | scene.RegionInfo.InternalEndPoint.Port = (int)port; | 87 | scene.RegionInfo.InternalEndPoint.Port = (int)port; |
87 | 88 | ||
88 | AddScene(scene); | 89 | AddScene(scene); |
89 | } | 90 | } |
90 | 91 | ||
91 | public void RemoveRegion(Scene scene) | 92 | public virtual void RemoveRegion(Scene scene) |
92 | { | 93 | { |
93 | Stop(); | 94 | Stop(); |
94 | } | 95 | } |
95 | 96 | ||
96 | public void RegionLoaded(Scene scene) | 97 | public virtual void RegionLoaded(Scene scene) |
97 | { | 98 | { |
98 | Start(); | 99 | Start(); |
99 | } | 100 | } |
100 | #endregion | 101 | #endregion |
101 | 102 | ||
102 | public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | 103 | public virtual void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, IConfigSource configSource, AgentCircuitManager circuitManager) |
103 | { | 104 | { |
104 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); | 105 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, configSource, circuitManager); |
105 | } | 106 | } |
106 | 107 | ||
107 | public void AddScene(IScene scene) | 108 | public virtual void AddScene(IScene scene) |
108 | { | 109 | { |
109 | m_udpServer.AddScene(scene); | 110 | m_udpServer.AddScene(scene); |
110 | 111 | ||
@@ -223,22 +224,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
223 | StatType.Pull, | 224 | StatType.Pull, |
224 | MeasuresOfInterest.None, | 225 | MeasuresOfInterest.None, |
225 | stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod, | 226 | stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod, |
226 | // stat => | 227 | // stat => |
227 | // stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7), | 228 | // stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7), |
228 | StatVerbosity.Debug)); | 229 | StatVerbosity.Debug)); |
229 | } | 230 | } |
230 | 231 | ||
231 | public bool HandlesRegion(Location x) | 232 | public virtual bool HandlesRegion(Location x) |
232 | { | 233 | { |
233 | return m_udpServer.HandlesRegion(x); | 234 | return m_udpServer.HandlesRegion(x); |
234 | } | 235 | } |
235 | 236 | ||
236 | public void Start() | 237 | public virtual void Start() |
237 | { | 238 | { |
238 | m_udpServer.Start(); | 239 | m_udpServer.Start(); |
239 | } | 240 | } |
240 | 241 | ||
241 | public void Stop() | 242 | public virtual void Stop() |
242 | { | 243 | { |
243 | m_udpServer.Stop(); | 244 | m_udpServer.Stop(); |
244 | } | 245 | } |
@@ -257,7 +258,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
257 | public const int MTU = 1400; | 258 | public const int MTU = 1400; |
258 | 259 | ||
259 | /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary> | 260 | /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary> |
260 | public int ClientLogoutsDueToNoReceives { get; private set; } | 261 | public int ClientLogoutsDueToNoReceives { get; protected set; } |
261 | 262 | ||
262 | /// <summary> | 263 | /// <summary> |
263 | /// Default packet debug level given to new clients | 264 | /// Default packet debug level given to new clients |
@@ -273,7 +274,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
273 | /// <summary>The measured resolution of Environment.TickCount</summary> | 274 | /// <summary>The measured resolution of Environment.TickCount</summary> |
274 | public readonly float TickCountResolution; | 275 | public readonly float TickCountResolution; |
275 | 276 | ||
276 | /// <summary>Number of prim updates to put on the queue each time the | 277 | /// <summary>Number of prim updates to put on the queue each time the |
277 | /// OnQueueEmpty event is triggered for updates</summary> | 278 | /// OnQueueEmpty event is triggered for updates</summary> |
278 | public readonly int PrimUpdatesPerCallback; | 279 | public readonly int PrimUpdatesPerCallback; |
279 | 280 | ||
@@ -284,54 +285,53 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
284 | /// <summary>Handlers for incoming packets</summary> | 285 | /// <summary>Handlers for incoming packets</summary> |
285 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); | 286 | //PacketEventDictionary packetEvents = new PacketEventDictionary(); |
286 | /// <summary>Incoming packets that are awaiting handling</summary> | 287 | /// <summary>Incoming packets that are awaiting handling</summary> |
287 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | 288 | //protected OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); |
289 | |||
290 | protected OpenSim.Framework.BlockingQueue<IncomingPacket> packetInbox = new OpenSim.Framework.BlockingQueue<IncomingPacket>(); | ||
288 | 291 | ||
289 | /// <summary>Bandwidth throttle for this UDP server</summary> | 292 | /// <summary>Bandwidth throttle for this UDP server</summary> |
290 | public TokenBucket Throttle { get; private set; } | 293 | public TokenBucket Throttle { get; protected set; } |
291 | 294 | ||
292 | /// <summary>Per client throttle rates enforced by this server</summary> | 295 | /// <summary>Per client throttle rates enforced by this server</summary> |
293 | /// <remarks> | 296 | /// <remarks> |
294 | /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have. | 297 | /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have. |
295 | /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually | 298 | /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually |
296 | /// do get changed immediately). They do not need to sum to the total. | 299 | /// do get changed immediately). They do not need to sum to the total. |
297 | /// </remarks> | 300 | /// </remarks> |
298 | public ThrottleRates ThrottleRates { get; private set; } | 301 | public ThrottleRates ThrottleRates { get; protected set; } |
299 | 302 | ||
300 | /// <summary>Manages authentication for agent circuits</summary> | 303 | /// <summary>Manages authentication for agent circuits</summary> |
301 | private AgentCircuitManager m_circuitManager; | 304 | protected AgentCircuitManager m_circuitManager; |
302 | 305 | ||
303 | /// <summary>Reference to the scene this UDP server is attached to</summary> | 306 | /// <summary>Reference to the scene this UDP server is attached to</summary> |
304 | public Scene Scene { get; private set; } | 307 | public Scene Scene { get; protected set; } |
305 | 308 | ||
306 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> | 309 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> |
307 | private Location m_location; | 310 | protected Location m_location; |
308 | 311 | ||
309 | /// <summary>The size of the receive buffer for the UDP socket. This value | 312 | /// <summary>The size of the receive buffer for the UDP socket. This value |
310 | /// is passed up to the operating system and used in the system networking | 313 | /// is passed up to the operating system and used in the system networking |
311 | /// stack. Use zero to leave this value as the default</summary> | 314 | /// stack. Use zero to leave this value as the default</summary> |
312 | private int m_recvBufferSize; | 315 | protected int m_recvBufferSize; |
313 | |||
314 | /// <summary>Flag to process packets asynchronously or synchronously</summary> | ||
315 | private bool m_asyncPacketHandling; | ||
316 | 316 | ||
317 | /// <summary>Tracks whether or not a packet was sent each round so we know | 317 | /// <summary>Tracks whether or not a packet was sent each round so we know |
318 | /// whether or not to sleep</summary> | 318 | /// whether or not to sleep</summary> |
319 | private bool m_packetSent; | 319 | protected bool m_packetSent; |
320 | 320 | ||
321 | /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> | 321 | /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> |
322 | private int m_elapsedMSSinceLastStatReport = 0; | 322 | protected int m_elapsedMSSinceLastStatReport = 0; |
323 | 323 | ||
324 | /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> | 324 | /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> |
325 | private int m_tickLastOutgoingPacketHandler; | 325 | protected double m_tickLastOutgoingPacketHandler; |
326 | 326 | ||
327 | /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> | 327 | /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> |
328 | private int m_elapsedMSOutgoingPacketHandler; | 328 | protected double m_elapsedMSOutgoingPacketHandler; |
329 | 329 | ||
330 | /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> | 330 | /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> |
331 | private int m_elapsed100MSOutgoingPacketHandler; | 331 | protected int m_elapsed100MSOutgoingPacketHandler; |
332 | 332 | ||
333 | /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> | 333 | /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> |
334 | private int m_elapsed500MSOutgoingPacketHandler; | 334 | protected int m_elapsed500MSOutgoingPacketHandler; |
335 | 335 | ||
336 | /// <summary>Flag to signal when clients should check for resends</summary> | 336 | /// <summary>Flag to signal when clients should check for resends</summary> |
337 | protected bool m_resendUnacked; | 337 | protected bool m_resendUnacked; |
@@ -342,32 +342,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
342 | /// <summary>Flag to signal when clients should send pings</summary> | 342 | /// <summary>Flag to signal when clients should send pings</summary> |
343 | protected bool m_sendPing; | 343 | protected bool m_sendPing; |
344 | 344 | ||
345 | /// <summary> | 345 | protected int m_animationSequenceNumber; |
346 | /// Event used to signal when queued packets are available for sending. | ||
347 | /// </summary> | ||
348 | /// <remarks> | ||
349 | /// This allows the outbound loop to only operate when there is data to send rather than continuously polling. | ||
350 | /// Some data is sent immediately and not queued. That data would not trigger this event. | ||
351 | /// </remarks> | ||
352 | private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); | ||
353 | 346 | ||
354 | private Pool<IncomingPacket> m_incomingPacketPool; | 347 | public int NextAnimationSequenceNumber |
348 | { | ||
349 | get | ||
350 | { | ||
351 | m_animationSequenceNumber++; | ||
352 | if (m_animationSequenceNumber > 2147482624) | ||
353 | m_animationSequenceNumber = 1; | ||
354 | return m_animationSequenceNumber; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | protected ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); | ||
359 | |||
360 | protected Pool<IncomingPacket> m_incomingPacketPool; | ||
355 | 361 | ||
356 | /// <summary> | 362 | /// <summary> |
357 | /// Stat for number of packets in the main pool awaiting use. | 363 | /// Stat for number of packets in the main pool awaiting use. |
358 | /// </summary> | 364 | /// </summary> |
359 | private Stat m_poolCountStat; | 365 | protected Stat m_poolCountStat; |
360 | 366 | ||
361 | /// <summary> | 367 | /// <summary> |
362 | /// Stat for number of packets in the inbound packet pool awaiting use. | 368 | /// Stat for number of packets in the inbound packet pool awaiting use. |
363 | /// </summary> | 369 | /// </summary> |
364 | private Stat m_incomingPacketPoolStat; | 370 | protected Stat m_incomingPacketPoolStat; |
365 | 371 | ||
366 | private int m_defaultRTO = 0; | 372 | protected int m_defaultRTO = 0; |
367 | private int m_maxRTO = 0; | 373 | protected int m_maxRTO = 0; |
368 | private int m_ackTimeout = 0; | 374 | protected int m_ackTimeout = 0; |
369 | private int m_pausedAckTimeout = 0; | 375 | protected int m_pausedAckTimeout = 0; |
370 | private bool m_disableFacelights = false; | 376 | protected bool m_disableFacelights = false; |
371 | 377 | ||
372 | public Socket Server { get { return null; } } | 378 | public Socket Server { get { return null; } } |
373 | 379 | ||
@@ -389,28 +395,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
389 | /// <summary> | 395 | /// <summary> |
390 | /// Record how many inbound packets could not be recognized as LLUDP packets. | 396 | /// Record how many inbound packets could not be recognized as LLUDP packets. |
391 | /// </summary> | 397 | /// </summary> |
392 | public int IncomingMalformedPacketCount { get; private set; } | 398 | public int IncomingMalformedPacketCount { get; protected set; } |
393 | 399 | ||
394 | /// <summary> | 400 | /// <summary> |
395 | /// Record how many inbound packets could not be associated with a simulator circuit. | 401 | /// Record how many inbound packets could not be associated with a simulator circuit. |
396 | /// </summary> | 402 | /// </summary> |
397 | public int IncomingOrphanedPacketCount { get; private set; } | 403 | public int IncomingOrphanedPacketCount { get; protected set; } |
398 | 404 | ||
399 | /// <summary> | 405 | /// <summary> |
400 | /// Record current outgoing client for monitoring purposes. | 406 | /// Record current outgoing client for monitoring purposes. |
401 | /// </summary> | 407 | /// </summary> |
402 | private IClientAPI m_currentOutgoingClient; | 408 | protected IClientAPI m_currentOutgoingClient; |
403 | 409 | ||
404 | /// <summary> | 410 | /// <summary> |
405 | /// Recording current incoming client for monitoring purposes. | 411 | /// Recording current incoming client for monitoring purposes. |
406 | /// </summary> | 412 | /// </summary> |
407 | private IClientAPI m_currentIncomingClient; | 413 | protected IClientAPI m_currentIncomingClient; |
408 | 414 | ||
409 | /// <summary> | 415 | /// <summary> |
410 | /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available | 416 | /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available |
411 | /// threadpool threads. | 417 | /// threadpool threads. |
412 | /// </summary> | 418 | /// </summary> |
413 | public JobEngine IpahEngine { get; private set; } | 419 | // public JobEngine IpahEngine { get; protected set; } |
414 | 420 | ||
415 | /// <summary> | 421 | /// <summary> |
416 | /// Run queue empty processing within a single persistent thread. | 422 | /// Run queue empty processing within a single persistent thread. |
@@ -420,27 +426,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
420 | /// connection schedule its own job in the threadpool which causes performance problems when there are many | 426 | /// connection schedule its own job in the threadpool which causes performance problems when there are many |
421 | /// connections. | 427 | /// connections. |
422 | /// </remarks> | 428 | /// </remarks> |
423 | public JobEngine OqrEngine { get; private set; } | 429 | public JobEngine OqrEngine { get; protected set; } |
424 | 430 | ||
425 | public LLUDPServer( | 431 | public LLUDPServer( |
426 | IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, | 432 | IPAddress listenIP, ref uint port, int proxyPortOffsetParm, |
427 | IConfigSource configSource, AgentCircuitManager circuitManager) | 433 | IConfigSource configSource, AgentCircuitManager circuitManager) |
428 | : base(listenIP, (int)port) | 434 | : base(listenIP, (int)port) |
429 | { | 435 | { |
430 | #region Environment.TickCount Measurement | 436 | #region Environment.TickCount Measurement |
431 | 437 | ||
438 | // Update the port with the one we actually got | ||
439 | port = (uint)Port; | ||
440 | |||
432 | // Measure the resolution of Environment.TickCount | 441 | // Measure the resolution of Environment.TickCount |
433 | TickCountResolution = 0f; | 442 | TickCountResolution = 0f; |
434 | for (int i = 0; i < 5; i++) | 443 | for (int i = 0; i < 10; i++) |
435 | { | 444 | { |
436 | int start = Environment.TickCount; | 445 | int start = Environment.TickCount; |
437 | int now = start; | 446 | int now = start; |
438 | while (now == start) | 447 | while (now == start) |
439 | now = Environment.TickCount; | 448 | now = Environment.TickCount; |
440 | TickCountResolution += (float)(now - start) * 0.2f; | 449 | TickCountResolution += (float)(now - start); |
450 | } | ||
451 | m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution * 0.1f + "ms"); | ||
452 | |||
453 | TickCountResolution = 0f; | ||
454 | for (int i = 0; i < 100; i++) | ||
455 | { | ||
456 | double start = Util.GetTimeStampMS(); | ||
457 | double now = start; | ||
458 | while (now == start) | ||
459 | now = Util.GetTimeStampMS(); | ||
460 | TickCountResolution += (float)((now - start)); | ||
441 | } | 461 | } |
442 | m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); | 462 | |
443 | TickCountResolution = (float)Math.Ceiling(TickCountResolution); | 463 | TickCountResolution = (float)Math.Round(TickCountResolution * 0.01f,6,MidpointRounding.AwayFromZero); |
464 | m_log.Info("[LLUDPSERVER]: Average Util.GetTimeStampMS resolution: " + TickCountResolution + "ms"); | ||
444 | 465 | ||
445 | #endregion Environment.TickCount Measurement | 466 | #endregion Environment.TickCount Measurement |
446 | 467 | ||
@@ -451,7 +472,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
451 | IConfig config = configSource.Configs["ClientStack.LindenUDP"]; | 472 | IConfig config = configSource.Configs["ClientStack.LindenUDP"]; |
452 | if (config != null) | 473 | if (config != null) |
453 | { | 474 | { |
454 | m_asyncPacketHandling = config.GetBoolean("async_packet_handling", true); | ||
455 | m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); | 475 | m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); |
456 | sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); | 476 | sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); |
457 | 477 | ||
@@ -494,24 +514,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
494 | } | 514 | } |
495 | #endregion BinaryStats | 515 | #endregion BinaryStats |
496 | 516 | ||
497 | // FIXME: Can't add info here because don't know scene yet. | 517 | Throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f); |
498 | // m_throttle | ||
499 | // = new TokenBucket( | ||
500 | // string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps); | ||
501 | |||
502 | Throttle = new TokenBucket("server throttle bucket", null, 0, sceneThrottleBps); | ||
503 | |||
504 | ThrottleRates = new ThrottleRates(configSource); | 518 | ThrottleRates = new ThrottleRates(configSource); |
505 | 519 | ||
506 | if (usePools) | 520 | Random rnd = new Random(Util.EnvironmentTickCount()); |
507 | EnablePools(); | 521 | m_animationSequenceNumber = rnd.Next(11474826); |
522 | |||
523 | // if (usePools) | ||
524 | // EnablePools(); | ||
525 | base.DisablePools(); | ||
508 | } | 526 | } |
509 | 527 | ||
510 | public void Start() | 528 | public void Start() |
511 | { | 529 | { |
512 | StartInbound(); | 530 | StartInbound(); |
513 | StartOutbound(); | 531 | StartOutbound(); |
514 | IpahEngine.Start(); | 532 | // IpahEngine.Start(); |
515 | OqrEngine.Start(); | 533 | OqrEngine.Start(); |
516 | 534 | ||
517 | m_elapsedMSSinceLastStatReport = Environment.TickCount; | 535 | m_elapsedMSSinceLastStatReport = Environment.TickCount; |
@@ -520,10 +538,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
520 | public void StartInbound() | 538 | public void StartInbound() |
521 | { | 539 | { |
522 | m_log.InfoFormat( | 540 | m_log.InfoFormat( |
523 | "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}", | 541 | "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server"); |
524 | m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools); | ||
525 | 542 | ||
526 | base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); | 543 | base.StartInbound(m_recvBufferSize); |
527 | 544 | ||
528 | // This thread will process the packets received that are placed on the packetInbox | 545 | // This thread will process the packets received that are placed on the packetInbox |
529 | WorkManager.StartThread( | 546 | WorkManager.StartThread( |
@@ -557,7 +574,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
557 | m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name); | 574 | m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name); |
558 | base.StopOutbound(); | 575 | base.StopOutbound(); |
559 | base.StopInbound(); | 576 | base.StopInbound(); |
560 | IpahEngine.Stop(); | 577 | // IpahEngine.Stop(); |
561 | OqrEngine.Stop(); | 578 | OqrEngine.Stop(); |
562 | } | 579 | } |
563 | 580 | ||
@@ -642,7 +659,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
642 | /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. | 659 | /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. |
643 | /// </summary> | 660 | /// </summary> |
644 | /// <returns></returns> | 661 | /// <returns></returns> |
645 | private string GetWatchdogIncomingAlarmData() | 662 | protected string GetWatchdogIncomingAlarmData() |
646 | { | 663 | { |
647 | return string.Format( | 664 | return string.Format( |
648 | "Client is {0}", | 665 | "Client is {0}", |
@@ -653,7 +670,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
653 | /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. | 670 | /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. |
654 | /// </summary> | 671 | /// </summary> |
655 | /// <returns></returns> | 672 | /// <returns></returns> |
656 | private string GetWatchdogOutgoingAlarmData() | 673 | protected string GetWatchdogOutgoingAlarmData() |
657 | { | 674 | { |
658 | return string.Format( | 675 | return string.Format( |
659 | "Client is {0}", | 676 | "Client is {0}", |
@@ -676,15 +693,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
676 | 693 | ||
677 | Scene = (Scene)scene; | 694 | Scene = (Scene)scene; |
678 | m_location = new Location(Scene.RegionInfo.RegionHandle); | 695 | m_location = new Location(Scene.RegionInfo.RegionHandle); |
679 | 696 | /* | |
680 | IpahEngine | 697 | IpahEngine |
681 | = new JobEngine( | 698 | = new JobEngine( |
682 | string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name), | 699 | string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name), |
683 | "INCOMING PACKET ASYNC HANDLING ENGINE"); | 700 | "INCOMING PACKET ASYNC HANDLING ENGINE"); |
684 | 701 | */ | |
685 | OqrEngine | 702 | OqrEngine |
686 | = new JobEngine( | 703 | = new JobEngine( |
687 | string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name), | 704 | string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name), |
688 | "OUTGOING QUEUE REFILL ENGINE"); | 705 | "OUTGOING QUEUE REFILL ENGINE"); |
689 | 706 | ||
690 | StatsManager.RegisterStat( | 707 | StatsManager.RegisterStat( |
@@ -697,7 +714,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
697 | scene.Name, | 714 | scene.Name, |
698 | StatType.Pull, | 715 | StatType.Pull, |
699 | MeasuresOfInterest.AverageChangeOverTime, | 716 | MeasuresOfInterest.AverageChangeOverTime, |
700 | stat => stat.Value = packetInbox.Count, | 717 | stat => stat.Value = packetInbox.Count(), |
701 | StatVerbosity.Debug)); | 718 | StatVerbosity.Debug)); |
702 | 719 | ||
703 | // XXX: These stats are also pool stats but we register them separately since they are currently not | 720 | // XXX: These stats are also pool stats but we register them separately since they are currently not |
@@ -710,9 +727,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
710 | "clientstack", | 727 | "clientstack", |
711 | Scene.Name, | 728 | Scene.Name, |
712 | StatType.Pull, | 729 | StatType.Pull, |
713 | stat => | 730 | stat => |
714 | { PercentageStat pstat = (PercentageStat)stat; | 731 | { PercentageStat pstat = (PercentageStat)stat; |
715 | pstat.Consequent = PacketPool.Instance.PacketsRequested; | 732 | pstat.Consequent = PacketPool.Instance.PacketsRequested; |
716 | pstat.Antecedent = PacketPool.Instance.PacketsReused; }, | 733 | pstat.Antecedent = PacketPool.Instance.PacketsReused; }, |
717 | StatVerbosity.Debug)); | 734 | StatVerbosity.Debug)); |
718 | 735 | ||
@@ -725,8 +742,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
725 | Scene.Name, | 742 | Scene.Name, |
726 | StatType.Pull, | 743 | StatType.Pull, |
727 | stat => | 744 | stat => |
728 | { PercentageStat pstat = (PercentageStat)stat; | 745 | { PercentageStat pstat = (PercentageStat)stat; |
729 | pstat.Consequent = PacketPool.Instance.BlocksRequested; | 746 | pstat.Consequent = PacketPool.Instance.BlocksRequested; |
730 | pstat.Antecedent = PacketPool.Instance.BlocksReused; }, | 747 | pstat.Antecedent = PacketPool.Instance.BlocksReused; }, |
731 | StatVerbosity.Debug)); | 748 | StatVerbosity.Debug)); |
732 | 749 | ||
@@ -766,7 +783,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
766 | MeasuresOfInterest.AverageChangeOverTime, | 783 | MeasuresOfInterest.AverageChangeOverTime, |
767 | stat => stat.Value = GetTotalQueuedOutgoingPackets(), | 784 | stat => stat.Value = GetTotalQueuedOutgoingPackets(), |
768 | StatVerbosity.Info)); | 785 | StatVerbosity.Info)); |
769 | 786 | /* | |
770 | StatsManager.RegisterStat( | 787 | StatsManager.RegisterStat( |
771 | new Stat( | 788 | new Stat( |
772 | "IncomingPacketAsyncRequestsWaiting", | 789 | "IncomingPacketAsyncRequestsWaiting", |
@@ -779,7 +796,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
779 | MeasuresOfInterest.None, | 796 | MeasuresOfInterest.None, |
780 | stat => stat.Value = IpahEngine.JobsWaiting, | 797 | stat => stat.Value = IpahEngine.JobsWaiting, |
781 | StatVerbosity.Debug)); | 798 | StatVerbosity.Debug)); |
782 | 799 | */ | |
783 | StatsManager.RegisterStat( | 800 | StatsManager.RegisterStat( |
784 | new Stat( | 801 | new Stat( |
785 | "OQRERequestsWaiting", | 802 | "OQRERequestsWaiting", |
@@ -792,14 +809,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
792 | MeasuresOfInterest.None, | 809 | MeasuresOfInterest.None, |
793 | stat => stat.Value = OqrEngine.JobsWaiting, | 810 | stat => stat.Value = OqrEngine.JobsWaiting, |
794 | StatVerbosity.Debug)); | 811 | StatVerbosity.Debug)); |
795 | 812 | ||
796 | // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by | 813 | // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by |
797 | // scene name | 814 | // scene name |
798 | if (UsePools) | 815 | if (UsePools) |
799 | EnablePoolStats(); | 816 | EnablePoolStats(); |
800 | 817 | ||
818 | |||
801 | LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this); | 819 | LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this); |
802 | commands.Register(); | 820 | commands.Register(); |
821 | |||
803 | } | 822 | } |
804 | 823 | ||
805 | public bool HandlesRegion(Location x) | 824 | public bool HandlesRegion(Location x) |
@@ -906,9 +925,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
906 | } | 925 | } |
907 | 926 | ||
908 | PacketPool.Instance.ReturnPacket(packet); | 927 | PacketPool.Instance.ReturnPacket(packet); |
909 | |||
910 | if (packetQueued) | ||
911 | m_dataPresentEvent.Set(); | ||
912 | } | 928 | } |
913 | 929 | ||
914 | /// <summary> | 930 | /// <summary> |
@@ -969,8 +985,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
969 | bufferSize = dataLength; | 985 | bufferSize = dataLength; |
970 | buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); | 986 | buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); |
971 | 987 | ||
972 | // m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + | 988 | m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + |
973 | // type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet"); | 989 | type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length); |
974 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | 990 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); |
975 | } | 991 | } |
976 | } | 992 | } |
@@ -979,35 +995,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
979 | 995 | ||
980 | #region Queue or Send | 996 | #region Queue or Send |
981 | 997 | ||
998 | bool highPriority = false; | ||
999 | |||
1000 | if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0) | ||
1001 | { | ||
1002 | category = (ThrottleOutPacketType)((int)category & 127); | ||
1003 | highPriority = true; | ||
1004 | } | ||
1005 | |||
982 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); | 1006 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); |
983 | 1007 | ||
984 | // If we were not provided a method for handling unacked, use the UDPServer default method | 1008 | // If we were not provided a method for handling unacked, use the UDPServer default method |
985 | if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0) | 1009 | if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0) |
986 | outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); | 1010 | outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); |
987 | 1011 | ||
988 | // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will | 1012 | // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will |
989 | // continue to display the deleted object until relog. Therefore, we need to always queue a kill object | 1013 | // continue to display the deleted object until relog. Therefore, we need to always queue a kill object |
990 | // packet so that it isn't sent before a queued update packet. | 1014 | // packet so that it isn't sent before a queued update packet. |
991 | bool forceQueue = (type == PacketType.KillObject); | ||
992 | 1015 | ||
993 | // if (type == PacketType.ImprovedTerseObjectUpdate) | 1016 | bool requestQueue = type == PacketType.KillObject; |
994 | // { | 1017 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority)) |
995 | // m_log.DebugFormat("Direct send ITOU to {0} in {1}", udpClient.AgentID, Scene.Name); | ||
996 | // SendPacketFinal(outgoingPacket); | ||
997 | // return false; | ||
998 | // } | ||
999 | // else | ||
1000 | // { | ||
1001 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, forceQueue)) | ||
1002 | { | 1018 | { |
1003 | SendPacketFinal(outgoingPacket); | 1019 | SendPacketFinal(outgoingPacket); |
1004 | return true; | 1020 | return true; |
1005 | } | 1021 | } |
1006 | else | 1022 | |
1007 | { | 1023 | return false; |
1008 | return false; | ||
1009 | } | ||
1010 | // } | ||
1011 | 1024 | ||
1012 | #endregion Queue or Send | 1025 | #endregion Queue or Send |
1013 | } | 1026 | } |
@@ -1048,6 +1061,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1048 | pc.PingID.OldestUnacked = 0; | 1061 | pc.PingID.OldestUnacked = 0; |
1049 | 1062 | ||
1050 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); | 1063 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); |
1064 | udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount(); | ||
1051 | } | 1065 | } |
1052 | 1066 | ||
1053 | public void CompletePing(LLUDPClient udpClient, byte pingID) | 1067 | public void CompletePing(LLUDPClient udpClient, byte pingID) |
@@ -1145,7 +1159,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1145 | int dataLength = buffer.DataLength; | 1159 | int dataLength = buffer.DataLength; |
1146 | 1160 | ||
1147 | // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here | 1161 | // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here |
1148 | if (!isZerocoded) | 1162 | if (!isZerocoded && !isResend && outgoingPacket.UnackedMethod == null) |
1149 | { | 1163 | { |
1150 | // Keep appending ACKs until there is no room left in the buffer or there are | 1164 | // Keep appending ACKs until there is no room left in the buffer or there are |
1151 | // no more ACKs to append | 1165 | // no more ACKs to append |
@@ -1180,7 +1194,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1180 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); | 1194 | Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); |
1181 | outgoingPacket.SequenceNumber = sequenceNumber; | 1195 | outgoingPacket.SequenceNumber = sequenceNumber; |
1182 | 1196 | ||
1183 | if (udpClient.ProcessUnackedSends && isReliable) | 1197 | if (isReliable) |
1184 | { | 1198 | { |
1185 | // Add this packet to the list of ACK responses we are waiting on from the server | 1199 | // Add this packet to the list of ACK responses we are waiting on from the server |
1186 | udpClient.NeedAcks.Add(outgoingPacket); | 1200 | udpClient.NeedAcks.Add(outgoingPacket); |
@@ -1210,13 +1224,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1210 | outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name); | 1224 | outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name); |
1211 | 1225 | ||
1212 | // Put the UDP payload on the wire | 1226 | // Put the UDP payload on the wire |
1213 | AsyncBeginSend(buffer); | 1227 | // AsyncBeginSend(buffer); |
1228 | SyncSend(buffer); | ||
1214 | 1229 | ||
1215 | // Keep track of when this packet was sent out (right now) | 1230 | // Keep track of when this packet was sent out (right now) |
1216 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; | 1231 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; |
1217 | } | 1232 | } |
1218 | 1233 | ||
1219 | private void RecordMalformedInboundPacket(IPEndPoint endPoint) | 1234 | protected void RecordMalformedInboundPacket(IPEndPoint endPoint) |
1220 | { | 1235 | { |
1221 | // if (m_malformedCount < 100) | 1236 | // if (m_malformedCount < 100) |
1222 | // m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); | 1237 | // m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); |
@@ -1225,7 +1240,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1225 | 1240 | ||
1226 | if ((IncomingMalformedPacketCount % 10000) == 0) | 1241 | if ((IncomingMalformedPacketCount % 10000) == 0) |
1227 | m_log.WarnFormat( | 1242 | m_log.WarnFormat( |
1228 | "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}", | 1243 | "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}", |
1229 | IncomingMalformedPacketCount, endPoint); | 1244 | IncomingMalformedPacketCount, endPoint); |
1230 | } | 1245 | } |
1231 | 1246 | ||
@@ -1298,8 +1313,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1298 | { | 1313 | { |
1299 | if (IncomingMalformedPacketCount < 100) | 1314 | if (IncomingMalformedPacketCount < 100) |
1300 | { | 1315 | { |
1301 | m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:", | 1316 | m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data as hex {2}: {3}", |
1302 | buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); | 1317 | buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null), |
1318 | Regex.Replace(Encoding.UTF8.GetString(buffer.Data, 0, buffer.DataLength), @"\p{Cc}", a=>string.Format("[{0:X2}]", (byte)a.Value[0]))); | ||
1303 | } | 1319 | } |
1304 | 1320 | ||
1305 | RecordMalformedInboundPacket(endPoint); | 1321 | RecordMalformedInboundPacket(endPoint); |
@@ -1311,35 +1327,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1311 | 1327 | ||
1312 | #region Packet to Client Mapping | 1328 | #region Packet to Client Mapping |
1313 | 1329 | ||
1314 | // UseCircuitCode handling | 1330 | // If there is already a client for this endpoint, don't process UseCircuitCode |
1315 | if (packet.Type == PacketType.UseCircuitCode) | 1331 | IClientAPI client = null; |
1332 | if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | ||
1316 | { | 1333 | { |
1317 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | 1334 | // UseCircuitCode handling |
1318 | // buffer. | 1335 | if (packet.Type == PacketType.UseCircuitCode) |
1319 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | 1336 | { |
1337 | // And if there is a UseCircuitCode pending, also drop it | ||
1338 | lock (m_pendingCache) | ||
1339 | { | ||
1340 | if (m_pendingCache.Contains(endPoint)) | ||
1341 | return; | ||
1320 | 1342 | ||
1321 | Util.FireAndForget(HandleUseCircuitCode, array, "LLUDPServer.HandleUseCircuitCode"); | 1343 | m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60); |
1344 | } | ||
1322 | 1345 | ||
1323 | return; | 1346 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the |
1347 | // buffer. | ||
1348 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
1349 | |||
1350 | Util.FireAndForget(HandleUseCircuitCode, array); | ||
1351 | |||
1352 | return; | ||
1353 | } | ||
1324 | } | 1354 | } |
1325 | else if (packet.Type == PacketType.CompleteAgentMovement) | 1355 | |
1356 | // If this is a pending connection, enqueue, don't process yet | ||
1357 | lock (m_pendingCache) | ||
1326 | { | 1358 | { |
1327 | // Send ack straight away to let the viewer know that we got it. | 1359 | Queue<UDPPacketBuffer> queue; |
1328 | SendAckImmediate(endPoint, packet.Header.Sequence); | 1360 | if (m_pendingCache.TryGetValue(endPoint, out queue)) |
1361 | { | ||
1362 | //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); | ||
1363 | queue.Enqueue(buffer); | ||
1364 | return; | ||
1365 | } | ||
1329 | 1366 | ||
1330 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the | 1367 | /* |
1331 | // buffer. | 1368 | else if (packet.Type == PacketType.CompleteAgentMovement) |
1332 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | 1369 | { |
1370 | // Send ack straight away to let the viewer know that we got it. | ||
1371 | SendAckImmediate(endPoint, packet.Header.Sequence); | ||
1333 | 1372 | ||
1334 | Util.FireAndForget( | 1373 | // We need to copy the endpoint so that it doesn't get changed when another thread reuses the |
1335 | HandleCompleteMovementIntoRegion, array, "LLUDPServer.HandleCompleteMovementIntoRegion"); | 1374 | // buffer. |
1375 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | ||
1336 | 1376 | ||
1337 | return; | 1377 | Util.FireAndForget(HandleCompleteMovementIntoRegion, array); |
1378 | |||
1379 | return; | ||
1380 | } | ||
1381 | */ | ||
1338 | } | 1382 | } |
1339 | 1383 | ||
1340 | // Determine which agent this packet came from | 1384 | // Determine which agent this packet came from |
1341 | IClientAPI client; | 1385 | if (client == null || !(client is LLClientView)) |
1342 | if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) | ||
1343 | { | 1386 | { |
1344 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 1387 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
1345 | 1388 | ||
@@ -1347,7 +1390,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1347 | 1390 | ||
1348 | if ((IncomingOrphanedPacketCount % 10000) == 0) | 1391 | if ((IncomingOrphanedPacketCount % 10000) == 0) |
1349 | m_log.WarnFormat( | 1392 | m_log.WarnFormat( |
1350 | "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}", | 1393 | "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}", |
1351 | IncomingOrphanedPacketCount, endPoint); | 1394 | IncomingOrphanedPacketCount, endPoint); |
1352 | 1395 | ||
1353 | return; | 1396 | return; |
@@ -1356,7 +1399,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1356 | udpClient = ((LLClientView)client).UDPClient; | 1399 | udpClient = ((LLClientView)client).UDPClient; |
1357 | 1400 | ||
1358 | if (!udpClient.IsConnected) | 1401 | if (!udpClient.IsConnected) |
1402 | { | ||
1403 | m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + Scene.RegionInfo.RegionName); | ||
1359 | return; | 1404 | return; |
1405 | } | ||
1360 | 1406 | ||
1361 | #endregion Packet to Client Mapping | 1407 | #endregion Packet to Client Mapping |
1362 | 1408 | ||
@@ -1368,37 +1414,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1368 | 1414 | ||
1369 | #region ACK Receiving | 1415 | #region ACK Receiving |
1370 | 1416 | ||
1371 | if (udpClient.ProcessUnackedSends) | 1417 | // Handle appended ACKs |
1418 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) | ||
1372 | { | 1419 | { |
1373 | // Handle appended ACKs | 1420 | // m_log.DebugFormat( |
1374 | if (packet.Header.AppendedAcks && packet.Header.AckList != null) | 1421 | // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}", |
1375 | { | 1422 | // packet.Header.AckList.Length, client.Name, m_scene.Name); |
1376 | // m_log.DebugFormat( | ||
1377 | // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}", | ||
1378 | // packet.Header.AckList.Length, client.Name, m_scene.Name); | ||
1379 | 1423 | ||
1380 | for (int i = 0; i < packet.Header.AckList.Length; i++) | 1424 | for (int i = 0; i < packet.Header.AckList.Length; i++) |
1381 | udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); | 1425 | udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); |
1382 | } | 1426 | } |
1383 | 1427 | ||
1384 | // Handle PacketAck packets | 1428 | // Handle PacketAck packets |
1385 | if (packet.Type == PacketType.PacketAck) | 1429 | if (packet.Type == PacketType.PacketAck) |
1386 | { | 1430 | { |
1387 | PacketAckPacket ackPacket = (PacketAckPacket)packet; | 1431 | PacketAckPacket ackPacket = (PacketAckPacket)packet; |
1388 | 1432 | ||
1389 | // m_log.DebugFormat( | 1433 | // m_log.DebugFormat( |
1390 | // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}", | 1434 | // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}", |
1391 | // ackPacket.Packets.Length, client.Name, m_scene.Name); | 1435 | // ackPacket.Packets.Length, client.Name, m_scene.Name); |
1392 | 1436 | ||
1393 | for (int i = 0; i < ackPacket.Packets.Length; i++) | 1437 | for (int i = 0; i < ackPacket.Packets.Length; i++) |
1394 | udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); | 1438 | udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); |
1395 | 1439 | ||
1396 | // We don't need to do anything else with PacketAck packets | 1440 | // We don't need to do anything else with PacketAck packets |
1397 | return; | ||
1398 | } | ||
1399 | } | ||
1400 | else if (packet.Type == PacketType.PacketAck) | ||
1401 | { | ||
1402 | return; | 1441 | return; |
1403 | } | 1442 | } |
1404 | 1443 | ||
@@ -1442,7 +1481,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1442 | { | 1481 | { |
1443 | if (packet.Header.Resent) | 1482 | if (packet.Header.Resent) |
1444 | m_log.DebugFormat( | 1483 | m_log.DebugFormat( |
1445 | "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}", | 1484 | "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}", |
1446 | packet.Header.Sequence, packet.Type, client.Name); | 1485 | packet.Header.Sequence, packet.Type, client.Name); |
1447 | else | 1486 | else |
1448 | m_log.WarnFormat( | 1487 | m_log.WarnFormat( |
@@ -1459,24 +1498,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1459 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); | 1498 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); |
1460 | #endregion BinaryStats | 1499 | #endregion BinaryStats |
1461 | 1500 | ||
1462 | if (packet.Type == PacketType.AgentUpdate) | ||
1463 | { | ||
1464 | if (DiscardInboundAgentUpdates) | ||
1465 | return; | ||
1466 | 1501 | ||
1467 | ((LLClientView)client).TotalAgentUpdates++; | 1502 | //AgentUpdate removed from here |
1468 | 1503 | ||
1469 | AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; | ||
1470 | |||
1471 | LLClientView llClient = client as LLClientView; | ||
1472 | if (agentUpdate.AgentData.SessionID != client.SessionId | ||
1473 | || agentUpdate.AgentData.AgentID != client.AgentId | ||
1474 | || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) ) | ||
1475 | { | ||
1476 | PacketPool.Instance.ReturnPacket(packet); | ||
1477 | return; | ||
1478 | } | ||
1479 | } | ||
1480 | 1504 | ||
1481 | #region Ping Check Handling | 1505 | #region Ping Check Handling |
1482 | 1506 | ||
@@ -1497,7 +1521,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1497 | } | 1521 | } |
1498 | else if (packet.Type == PacketType.CompletePingCheck) | 1522 | else if (packet.Type == PacketType.CompletePingCheck) |
1499 | { | 1523 | { |
1500 | // We don't currently track client ping times | 1524 | int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS); |
1525 | int c = udpClient.m_pingMS; | ||
1526 | c = 800 * c + 200 * t; | ||
1527 | c /= 1000; | ||
1528 | udpClient.m_pingMS = c; | ||
1501 | return; | 1529 | return; |
1502 | } | 1530 | } |
1503 | 1531 | ||
@@ -1517,7 +1545,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1517 | incomingPacket = new IncomingPacket((LLClientView)client, packet); | 1545 | incomingPacket = new IncomingPacket((LLClientView)client, packet); |
1518 | } | 1546 | } |
1519 | 1547 | ||
1520 | packetInbox.Enqueue(incomingPacket); | 1548 | // if (incomingPacket.Packet.Type == PacketType.AgentUpdate || |
1549 | // incomingPacket.Packet.Type == PacketType.ChatFromViewer) | ||
1550 | if (incomingPacket.Packet.Type == PacketType.ChatFromViewer) | ||
1551 | packetInbox.PriorityEnqueue(incomingPacket); | ||
1552 | else | ||
1553 | packetInbox.Enqueue(incomingPacket); | ||
1554 | |||
1521 | } | 1555 | } |
1522 | 1556 | ||
1523 | #region BinaryStats | 1557 | #region BinaryStats |
@@ -1627,14 +1661,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1627 | 1661 | ||
1628 | #endregion BinaryStats | 1662 | #endregion BinaryStats |
1629 | 1663 | ||
1630 | private void HandleUseCircuitCode(object o) | 1664 | protected void HandleUseCircuitCode(object o) |
1631 | { | 1665 | { |
1632 | IPEndPoint endPoint = null; | 1666 | IPEndPoint endPoint = null; |
1633 | IClientAPI client = null; | 1667 | IClientAPI client = null; |
1634 | 1668 | ||
1635 | try | 1669 | try |
1636 | { | 1670 | { |
1637 | // DateTime startTime = DateTime.Now; | 1671 | // DateTime startTime = DateTime.Now; |
1638 | object[] array = (object[])o; | 1672 | object[] array = (object[])o; |
1639 | endPoint = (IPEndPoint)array[0]; | 1673 | endPoint = (IPEndPoint)array[0]; |
1640 | UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; | 1674 | UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; |
@@ -1642,10 +1676,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1642 | m_log.DebugFormat( | 1676 | m_log.DebugFormat( |
1643 | "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", | 1677 | "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", |
1644 | uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint); | 1678 | uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint); |
1645 | 1679 | ||
1646 | AuthenticateResponse sessionInfo; | 1680 | AuthenticateResponse sessionInfo; |
1647 | if (IsClientAuthorized(uccp, out sessionInfo)) | 1681 | if (IsClientAuthorized(uccp, out sessionInfo)) |
1648 | { | 1682 | { |
1683 | AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); | ||
1684 | |||
1649 | // Begin the process of adding the client to the simulator | 1685 | // Begin the process of adding the client to the simulator |
1650 | client | 1686 | client |
1651 | = AddClient( | 1687 | = AddClient( |
@@ -1654,20 +1690,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1654 | uccp.CircuitCode.SessionID, | 1690 | uccp.CircuitCode.SessionID, |
1655 | endPoint, | 1691 | endPoint, |
1656 | sessionInfo); | 1692 | sessionInfo); |
1657 | 1693 | ||
1694 | // This will be true if the client is new, e.g. not | ||
1695 | // an existing child agent, and there is no circuit data | ||
1696 | if (client != null && aCircuit == null) | ||
1697 | { | ||
1698 | Scene.CloseAgent(client.AgentId, true); | ||
1699 | return; | ||
1700 | } | ||
1701 | |||
1702 | // Now we know we can handle more data | ||
1703 | Thread.Sleep(200); | ||
1704 | |||
1705 | // Obtain the pending queue and remove it from the cache | ||
1706 | Queue<UDPPacketBuffer> queue = null; | ||
1707 | |||
1708 | lock (m_pendingCache) | ||
1709 | { | ||
1710 | if (!m_pendingCache.TryGetValue(endPoint, out queue)) | ||
1711 | { | ||
1712 | m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); | ||
1713 | return; | ||
1714 | |||
1715 | } | ||
1716 | m_pendingCache.Remove(endPoint); | ||
1717 | } | ||
1718 | |||
1719 | m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); | ||
1720 | |||
1721 | // Reinject queued packets | ||
1722 | while (queue.Count > 0) | ||
1723 | { | ||
1724 | UDPPacketBuffer buf = queue.Dequeue(); | ||
1725 | PacketReceived(buf); | ||
1726 | } | ||
1727 | |||
1728 | queue = null; | ||
1729 | |||
1658 | // Send ack straight away to let the viewer know that the connection is active. | 1730 | // Send ack straight away to let the viewer know that the connection is active. |
1659 | // The client will be null if it already exists (e.g. if on a region crossing the client sends a use | 1731 | // The client will be null if it already exists (e.g. if on a region crossing the client sends a use |
1660 | // circuit code to the existing child agent. This is not particularly obvious. | 1732 | // circuit code to the existing child agent. This is not particularly obvious. |
1661 | SendAckImmediate(endPoint, uccp.Header.Sequence); | 1733 | SendAckImmediate(endPoint, uccp.Header.Sequence); |
1662 | 1734 | ||
1663 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1735 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1664 | if (client != null) | 1736 | if (client != null) |
1665 | { | 1737 | { |
1666 | AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); | ||
1667 | bool tp = (aCircuit.teleportFlags > 0); | 1738 | bool tp = (aCircuit.teleportFlags > 0); |
1668 | // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from | 1739 | // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from |
1669 | if (!tp && !client.SceneAgent.SentInitialDataToClient) | 1740 | if (!tp) |
1670 | client.SceneAgent.SendInitialDataToClient(); | 1741 | client.SceneAgent.SendInitialDataToMe(); |
1671 | } | 1742 | } |
1672 | } | 1743 | } |
1673 | else | 1744 | else |
@@ -1675,11 +1746,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1675 | // Don't create clients for unauthorized requesters. | 1746 | // Don't create clients for unauthorized requesters. |
1676 | m_log.WarnFormat( | 1747 | m_log.WarnFormat( |
1677 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", | 1748 | "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", |
1749 | |||
1678 | uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); | 1750 | uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); |
1751 | |||
1752 | lock (m_pendingCache) | ||
1753 | m_pendingCache.Remove(endPoint); | ||
1679 | } | 1754 | } |
1680 | 1755 | ||
1681 | // m_log.DebugFormat( | 1756 | // m_log.DebugFormat( |
1682 | // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", | 1757 | // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", |
1683 | // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); | 1758 | // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); |
1684 | 1759 | ||
1685 | } | 1760 | } |
@@ -1694,8 +1769,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1694 | e.StackTrace); | 1769 | e.StackTrace); |
1695 | } | 1770 | } |
1696 | } | 1771 | } |
1697 | 1772 | /* | |
1698 | private void HandleCompleteMovementIntoRegion(object o) | 1773 | protected void HandleCompleteMovementIntoRegion(object o) |
1699 | { | 1774 | { |
1700 | IPEndPoint endPoint = null; | 1775 | IPEndPoint endPoint = null; |
1701 | IClientAPI client = null; | 1776 | IClientAPI client = null; |
@@ -1711,9 +1786,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1711 | 1786 | ||
1712 | // Determine which agent this packet came from | 1787 | // Determine which agent this packet came from |
1713 | // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination | 1788 | // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination |
1714 | // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode | 1789 | // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode |
1715 | // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these | 1790 | // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these |
1716 | // packets asynchronously, we need to account for this thread proceeding more quickly than the | 1791 | // packets asynchronously, we need to account for this thread proceeding more quickly than the |
1717 | // UseCircuitCode thread. | 1792 | // UseCircuitCode thread. |
1718 | int count = 40; | 1793 | int count = 40; |
1719 | while (count-- > 0) | 1794 | while (count-- > 0) |
@@ -1735,7 +1810,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1735 | // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too | 1810 | // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too |
1736 | // eager, then the new ScenePresence may not have registered a listener for this messsage | 1811 | // eager, then the new ScenePresence may not have registered a listener for this messsage |
1737 | // before we try to process it. | 1812 | // before we try to process it. |
1738 | // XXX: A better long term fix may be to add the SceneAgent before the client is added to | 1813 | // XXX: A better long term fix may be to add the SceneAgent before the client is added to |
1739 | // the client manager | 1814 | // the client manager |
1740 | m_log.DebugFormat( | 1815 | m_log.DebugFormat( |
1741 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", | 1816 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", |
@@ -1749,7 +1824,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1749 | else | 1824 | else |
1750 | { | 1825 | { |
1751 | m_log.DebugFormat( | 1826 | m_log.DebugFormat( |
1752 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", | 1827 | "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", |
1753 | endPoint, Scene.Name); | 1828 | endPoint, Scene.Name); |
1754 | } | 1829 | } |
1755 | 1830 | ||
@@ -1804,6 +1879,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1804 | e.StackTrace); | 1879 | e.StackTrace); |
1805 | } | 1880 | } |
1806 | } | 1881 | } |
1882 | */ | ||
1807 | 1883 | ||
1808 | /// <summary> | 1884 | /// <summary> |
1809 | /// Send an ack immediately to the given endpoint. | 1885 | /// Send an ack immediately to the given endpoint. |
@@ -1814,7 +1890,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1814 | /// </remarks> | 1890 | /// </remarks> |
1815 | /// <param name="remoteEndpoint"></param> | 1891 | /// <param name="remoteEndpoint"></param> |
1816 | /// <param name="sequenceNumber"></param> | 1892 | /// <param name="sequenceNumber"></param> |
1817 | private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber) | 1893 | protected void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber) |
1818 | { | 1894 | { |
1819 | PacketAckPacket ack = new PacketAckPacket(); | 1895 | PacketAckPacket ack = new PacketAckPacket(); |
1820 | ack.Header.Reliable = false; | 1896 | ack.Header.Reliable = false; |
@@ -1835,10 +1911,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1835 | 1911 | ||
1836 | Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length); | 1912 | Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length); |
1837 | 1913 | ||
1838 | AsyncBeginSend(buffer); | 1914 | // AsyncBeginSend(buffer); |
1915 | SyncSend(buffer); | ||
1839 | } | 1916 | } |
1840 | 1917 | ||
1841 | private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) | 1918 | protected bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) |
1842 | { | 1919 | { |
1843 | UUID agentID = useCircuitCode.CircuitCode.ID; | 1920 | UUID agentID = useCircuitCode.CircuitCode.ID; |
1844 | UUID sessionID = useCircuitCode.CircuitCode.SessionID; | 1921 | UUID sessionID = useCircuitCode.CircuitCode.SessionID; |
@@ -1861,6 +1938,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1861 | uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) | 1938 | uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) |
1862 | { | 1939 | { |
1863 | IClientAPI client = null; | 1940 | IClientAPI client = null; |
1941 | bool createNew = false; | ||
1864 | 1942 | ||
1865 | // We currently synchronize this code across the whole scene to avoid issues such as | 1943 | // We currently synchronize this code across the whole scene to avoid issues such as |
1866 | // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done | 1944 | // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done |
@@ -1869,14 +1947,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1869 | { | 1947 | { |
1870 | if (!Scene.TryGetClient(agentID, out client)) | 1948 | if (!Scene.TryGetClient(agentID, out client)) |
1871 | { | 1949 | { |
1950 | createNew = true; | ||
1951 | } | ||
1952 | else | ||
1953 | { | ||
1954 | if (client.SceneAgent == null) | ||
1955 | { | ||
1956 | Scene.CloseAgent(agentID, true); | ||
1957 | createNew = true; | ||
1958 | } | ||
1959 | } | ||
1960 | |||
1961 | if (createNew) | ||
1962 | { | ||
1872 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); | 1963 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); |
1873 | 1964 | ||
1965 | |||
1874 | client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | 1966 | client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); |
1875 | client.OnLogout += LogoutHandler; | 1967 | client.OnLogout += LogoutHandler; |
1876 | client.DebugPacketLevel = DefaultClientPacketDebugLevel; | 1968 | client.DebugPacketLevel = DefaultClientPacketDebugLevel; |
1877 | 1969 | ||
1878 | ((LLClientView)client).DisableFacelights = m_disableFacelights; | 1970 | ((LLClientView)client).DisableFacelights = m_disableFacelights; |
1879 | 1971 | ||
1880 | client.Start(); | 1972 | client.Start(); |
1881 | } | 1973 | } |
1882 | } | 1974 | } |
@@ -1893,56 +1985,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1893 | /// </remarks> | 1985 | /// </remarks> |
1894 | /// <param name='client'></param> | 1986 | /// <param name='client'></param> |
1895 | /// <param name='timeoutTicks'></param> | 1987 | /// <param name='timeoutTicks'></param> |
1896 | private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) | 1988 | protected void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) |
1897 | { | 1989 | { |
1898 | lock (client.CloseSyncLock) | 1990 | lock (client.CloseSyncLock) |
1899 | { | 1991 | { |
1900 | ClientLogoutsDueToNoReceives++; | 1992 | ClientLogoutsDueToNoReceives++; |
1901 | 1993 | ||
1902 | m_log.WarnFormat( | 1994 | if (client.SceneAgent != null) |
1903 | "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.", | 1995 | { |
1904 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name); | 1996 | m_log.WarnFormat( |
1905 | 1997 | "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.", | |
1906 | if (!client.SceneAgent.IsChildAgent) | 1998 | client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name); |
1907 | client.Kick("Simulator logged you out due to connection timeout."); | 1999 | |
2000 | if (!client.SceneAgent.IsChildAgent) | ||
2001 | client.Kick("Simulator logged you out due to connection timeout."); | ||
2002 | } | ||
1908 | } | 2003 | } |
1909 | 2004 | ||
1910 | Scene.CloseAgent(client.AgentId, true); | 2005 | if (!Scene.CloseAgent(client.AgentId, true)) |
2006 | client.Close(true,true); | ||
1911 | } | 2007 | } |
1912 | 2008 | ||
1913 | private void IncomingPacketHandler() | 2009 | protected void IncomingPacketHandler() |
1914 | { | 2010 | { |
1915 | Thread.CurrentThread.Priority = ThreadPriority.Highest; | 2011 | Thread.CurrentThread.Priority = ThreadPriority.Highest; |
1916 | 2012 | IncomingPacket incomingPacket; | |
1917 | // Set this culture for the thread that incoming packets are received | 2013 | // Set this culture for the thread that incoming packets are received |
1918 | // on to en-US to avoid number parsing issues | 2014 | // on to en-US to avoid number parsing issues |
1919 | Culture.SetCurrentCulture(); | 2015 | Culture.SetCurrentCulture(); |
1920 | 2016 | ||
1921 | while (IsRunningInbound) | 2017 | while (IsRunningInbound) |
1922 | { | 2018 | { |
2019 | Scene.ThreadAlive(1); | ||
1923 | try | 2020 | try |
1924 | { | 2021 | { |
1925 | IncomingPacket incomingPacket = null; | 2022 | incomingPacket = packetInbox.Dequeue(250); |
1926 | |||
1927 | /* | ||
1928 | // HACK: This is a test to try and rate limit packet handling on Mono. | ||
1929 | // If it works, a more elegant solution can be devised | ||
1930 | if (Util.FireAndForgetCount() < 2) | ||
1931 | { | ||
1932 | //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); | ||
1933 | Thread.Sleep(30); | ||
1934 | } | ||
1935 | */ | ||
1936 | 2023 | ||
1937 | if (packetInbox.Dequeue(100, ref incomingPacket)) | 2024 | if (incomingPacket != null && IsRunningInbound) |
1938 | { | 2025 | { |
1939 | ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket); | 2026 | ProcessInPacket(incomingPacket); |
1940 | 2027 | ||
1941 | if (UsePools) | 2028 | if (UsePools) |
2029 | { | ||
2030 | incomingPacket.Client = null; | ||
1942 | m_incomingPacketPool.ReturnObject(incomingPacket); | 2031 | m_incomingPacketPool.ReturnObject(incomingPacket); |
2032 | } | ||
2033 | incomingPacket = null; | ||
1943 | } | 2034 | } |
1944 | } | 2035 | } |
1945 | catch (Exception ex) | 2036 | catch(Exception ex) |
1946 | { | 2037 | { |
1947 | m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); | 2038 | m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); |
1948 | } | 2039 | } |
@@ -1950,14 +2041,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1950 | Watchdog.UpdateThread(); | 2041 | Watchdog.UpdateThread(); |
1951 | } | 2042 | } |
1952 | 2043 | ||
1953 | if (packetInbox.Count > 0) | 2044 | if (packetInbox.Count() > 0) |
1954 | m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count + " packets"); | 2045 | m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count() + " packets"); |
1955 | packetInbox.Clear(); | 2046 | packetInbox.Clear(); |
1956 | 2047 | ||
1957 | Watchdog.RemoveThread(); | 2048 | Watchdog.RemoveThread(); |
1958 | } | 2049 | } |
1959 | 2050 | ||
1960 | private void OutgoingPacketHandler() | 2051 | protected void OutgoingPacketHandler() |
1961 | { | 2052 | { |
1962 | Thread.CurrentThread.Priority = ThreadPriority.Highest; | 2053 | Thread.CurrentThread.Priority = ThreadPriority.Highest; |
1963 | 2054 | ||
@@ -1971,6 +2062,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1971 | 2062 | ||
1972 | while (base.IsRunningOutbound) | 2063 | while (base.IsRunningOutbound) |
1973 | { | 2064 | { |
2065 | Scene.ThreadAlive(2); | ||
2066 | |||
2067 | |||
1974 | try | 2068 | try |
1975 | { | 2069 | { |
1976 | m_packetSent = false; | 2070 | m_packetSent = false; |
@@ -1982,19 +2076,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1982 | m_sendPing = false; | 2076 | m_sendPing = false; |
1983 | 2077 | ||
1984 | // Update elapsed time | 2078 | // Update elapsed time |
1985 | int thisTick = Environment.TickCount & Int32.MaxValue; | 2079 | double thisTick = Util.GetTimeStampMS(); |
1986 | if (m_tickLastOutgoingPacketHandler > thisTick) | ||
1987 | m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick); | ||
1988 | else | ||
1989 | m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler); | ||
1990 | 2080 | ||
2081 | // update some 1ms resolution chained timers | ||
2082 | m_elapsedMSOutgoingPacketHandler += thisTick - m_tickLastOutgoingPacketHandler; | ||
1991 | m_tickLastOutgoingPacketHandler = thisTick; | 2083 | m_tickLastOutgoingPacketHandler = thisTick; |
1992 | 2084 | ||
1993 | // Check for pending outgoing resends every 100ms | 2085 | // Check for pending outgoing resends every 100ms |
1994 | if (m_elapsedMSOutgoingPacketHandler >= 100) | 2086 | if (m_elapsedMSOutgoingPacketHandler >= 100.0) |
1995 | { | 2087 | { |
1996 | m_resendUnacked = true; | 2088 | m_resendUnacked = true; |
1997 | m_elapsedMSOutgoingPacketHandler = 0; | 2089 | m_elapsedMSOutgoingPacketHandler = 0.0; |
1998 | m_elapsed100MSOutgoingPacketHandler += 1; | 2090 | m_elapsed100MSOutgoingPacketHandler += 1; |
1999 | } | 2091 | } |
2000 | 2092 | ||
@@ -2012,15 +2104,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2012 | m_sendPing = true; | 2104 | m_sendPing = true; |
2013 | m_elapsed500MSOutgoingPacketHandler = 0; | 2105 | m_elapsed500MSOutgoingPacketHandler = 0; |
2014 | } | 2106 | } |
2015 | |||
2016 | #endregion Update Timers | 2107 | #endregion Update Timers |
2017 | 2108 | ||
2018 | // Use this for emergency monitoring -- bug hunting | ||
2019 | //if (m_scene.EmergencyMonitoring) | ||
2020 | // clientPacketHandler = MonitoredClientOutgoingPacketHandler; | ||
2021 | //else | ||
2022 | // clientPacketHandler = ClientOutgoingPacketHandler; | ||
2023 | |||
2024 | // Handle outgoing packets, resends, acknowledgements, and pings for each | 2109 | // Handle outgoing packets, resends, acknowledgements, and pings for each |
2025 | // client. m_packetSent will be set to true if a packet is sent | 2110 | // client. m_packetSent will be set to true if a packet is sent |
2026 | Scene.ForEachClient(clientPacketHandler); | 2111 | Scene.ForEachClient(clientPacketHandler); |
@@ -2029,13 +2114,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2029 | 2114 | ||
2030 | // If nothing was sent, sleep for the minimum amount of time before a | 2115 | // If nothing was sent, sleep for the minimum amount of time before a |
2031 | // token bucket could get more tokens | 2116 | // token bucket could get more tokens |
2032 | //if (!m_packetSent) | 2117 | |
2033 | // Thread.Sleep((int)TickCountResolution); | 2118 | if(Scene.GetNumberOfClients() == 0) |
2034 | // | 2119 | { |
2035 | // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with | 2120 | Thread.Sleep(100); |
2036 | // modern mono it reduces CPU base load since there is no more continuous polling. | 2121 | } |
2037 | if (!m_packetSent) | 2122 | else if (!m_packetSent) |
2038 | m_dataPresentEvent.WaitOne(100); | 2123 | // Thread.Sleep((int)TickCountResolution); outch this is bad on linux |
2124 | Thread.Sleep(15); // match the 16ms of windows7, dont ask 16 or win may decide to do 32ms. | ||
2039 | 2125 | ||
2040 | Watchdog.UpdateThread(); | 2126 | Watchdog.UpdateThread(); |
2041 | } | 2127 | } |
@@ -2061,7 +2147,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2061 | 2147 | ||
2062 | if (udpClient.IsConnected) | 2148 | if (udpClient.IsConnected) |
2063 | { | 2149 | { |
2064 | if (udpClient.ProcessUnackedSends && m_resendUnacked) | 2150 | if (m_resendUnacked) |
2065 | HandleUnacked(llClient); | 2151 | HandleUnacked(llClient); |
2066 | 2152 | ||
2067 | if (m_sendAcks) | 2153 | if (m_sendAcks) |
@@ -2086,160 +2172,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2086 | #region Emergency Monitoring | 2172 | #region Emergency Monitoring |
2087 | // Alternative packet handler fuull of instrumentation | 2173 | // Alternative packet handler fuull of instrumentation |
2088 | // Handy for hunting bugs | 2174 | // Handy for hunting bugs |
2089 | private Stopwatch watch1 = new Stopwatch(); | 2175 | protected Stopwatch watch1 = new Stopwatch(); |
2090 | private Stopwatch watch2 = new Stopwatch(); | 2176 | protected Stopwatch watch2 = new Stopwatch(); |
2091 | 2177 | ||
2092 | private float avgProcessingTicks = 0; | 2178 | protected float avgProcessingTicks = 0; |
2093 | private float avgResendUnackedTicks = 0; | 2179 | protected float avgResendUnackedTicks = 0; |
2094 | private float avgSendAcksTicks = 0; | 2180 | protected float avgSendAcksTicks = 0; |
2095 | private float avgSendPingTicks = 0; | 2181 | protected float avgSendPingTicks = 0; |
2096 | private float avgDequeueTicks = 0; | 2182 | protected float avgDequeueTicks = 0; |
2097 | private long nticks = 0; | 2183 | protected long nticks = 0; |
2098 | private long nticksUnack = 0; | 2184 | protected long nticksUnack = 0; |
2099 | private long nticksAck = 0; | 2185 | protected long nticksAck = 0; |
2100 | private long nticksPing = 0; | 2186 | protected long nticksPing = 0; |
2101 | private int npacksSent = 0; | 2187 | protected int npacksSent = 0; |
2102 | private int npackNotSent = 0; | 2188 | protected int npackNotSent = 0; |
2103 | 2189 | ||
2104 | /// <summary> | 2190 | /// <summary> |
2105 | /// Number of inbound packets processed since startup. | 2191 | /// Number of inbound packets processed since startup. |
2106 | /// </summary> | 2192 | /// </summary> |
2107 | public long IncomingPacketsProcessed { get; private set; } | 2193 | public long IncomingPacketsProcessed { get; protected set; } |
2108 | |||
2109 | private void MonitoredClientOutgoingPacketHandler(IClientAPI client) | ||
2110 | { | ||
2111 | nticks++; | ||
2112 | watch1.Start(); | ||
2113 | m_currentOutgoingClient = client; | ||
2114 | |||
2115 | try | ||
2116 | { | ||
2117 | if (client is LLClientView) | ||
2118 | { | ||
2119 | LLClientView llClient = (LLClientView)client; | ||
2120 | LLUDPClient udpClient = llClient.UDPClient; | ||
2121 | 2194 | ||
2122 | if (udpClient.IsConnected) | 2195 | #endregion |
2123 | { | ||
2124 | if (m_resendUnacked) | ||
2125 | { | ||
2126 | nticksUnack++; | ||
2127 | watch2.Start(); | ||
2128 | |||
2129 | HandleUnacked(llClient); | ||
2130 | |||
2131 | watch2.Stop(); | ||
2132 | avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); | ||
2133 | watch2.Reset(); | ||
2134 | } | ||
2135 | |||
2136 | if (m_sendAcks) | ||
2137 | { | ||
2138 | nticksAck++; | ||
2139 | watch2.Start(); | ||
2140 | |||
2141 | SendAcks(udpClient); | ||
2142 | |||
2143 | watch2.Stop(); | ||
2144 | avgSendAcksTicks = (nticksAck - 1) / (float)nticksAck * avgSendAcksTicks + (watch2.ElapsedTicks / (float)nticksAck); | ||
2145 | watch2.Reset(); | ||
2146 | } | ||
2147 | |||
2148 | if (m_sendPing) | ||
2149 | { | ||
2150 | nticksPing++; | ||
2151 | watch2.Start(); | ||
2152 | |||
2153 | SendPing(udpClient); | ||
2154 | 2196 | ||
2155 | watch2.Stop(); | 2197 | protected void ProcessInPacket(IncomingPacket incomingPacket) |
2156 | avgSendPingTicks = (nticksPing - 1) / (float)nticksPing * avgSendPingTicks + (watch2.ElapsedTicks / (float)nticksPing); | 2198 | { |
2157 | watch2.Reset(); | 2199 | Packet packet = incomingPacket.Packet; |
2158 | } | 2200 | LLClientView client = incomingPacket.Client; |
2159 | 2201 | ||
2160 | watch2.Start(); | 2202 | if(!client.IsActive) |
2161 | // Dequeue any outgoing packets that are within the throttle limits | 2203 | return; |
2162 | if (udpClient.DequeueOutgoing()) | ||
2163 | { | ||
2164 | m_packetSent = true; | ||
2165 | npacksSent++; | ||
2166 | } | ||
2167 | else | ||
2168 | { | ||
2169 | npackNotSent++; | ||
2170 | } | ||
2171 | 2204 | ||
2172 | watch2.Stop(); | 2205 | m_currentIncomingClient = client; |
2173 | avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks); | ||
2174 | watch2.Reset(); | ||
2175 | 2206 | ||
2176 | } | 2207 | try |
2177 | else | ||
2178 | { | ||
2179 | m_log.WarnFormat("[LLUDPSERVER]: Client is not connected"); | ||
2180 | } | ||
2181 | } | ||
2182 | } | ||
2183 | catch (Exception ex) | ||
2184 | { | 2208 | { |
2185 | m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + | 2209 | // Process this packet |
2186 | " threw an exception: " + ex.Message, ex); | 2210 | client.ProcessInPacket(packet); |
2187 | } | 2211 | } |
2188 | watch1.Stop(); | 2212 | catch(ThreadAbortException) |
2189 | avgProcessingTicks = (nticks - 1) / (float)nticks * avgProcessingTicks + (watch1.ElapsedTicks / (float)nticks); | ||
2190 | watch1.Reset(); | ||
2191 | |||
2192 | // reuse this -- it's every ~100ms | ||
2193 | if (Scene.EmergencyMonitoring && nticks % 100 == 0) | ||
2194 | { | 2213 | { |
2195 | m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})", | 2214 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down |
2196 | avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent); | 2215 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); |
2197 | npackNotSent = npacksSent = 0; | 2216 | Stop(); |
2198 | } | 2217 | } |
2199 | 2218 | catch(Exception e) | |
2200 | } | ||
2201 | |||
2202 | #endregion | ||
2203 | |||
2204 | private void ProcessInPacket(IncomingPacket incomingPacket) | ||
2205 | { | ||
2206 | Packet packet = incomingPacket.Packet; | ||
2207 | LLClientView client = incomingPacket.Client; | ||
2208 | |||
2209 | if (client.IsActive) | ||
2210 | { | 2219 | { |
2211 | m_currentIncomingClient = client; | 2220 | // Don't let a failure in an individual client thread crash the whole sim. |
2212 | 2221 | m_log.Error( | |
2213 | try | 2222 | string.Format( |
2214 | { | 2223 | "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ", |
2215 | // Process this packet | 2224 | client.Name,packet.Type), |
2216 | client.ProcessInPacket(packet); | 2225 | e); |
2217 | } | ||
2218 | catch (ThreadAbortException) | ||
2219 | { | ||
2220 | // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down | ||
2221 | m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); | ||
2222 | Stop(); | ||
2223 | } | ||
2224 | catch (Exception e) | ||
2225 | { | ||
2226 | // Don't let a failure in an individual client thread crash the whole sim. | ||
2227 | m_log.Error( | ||
2228 | string.Format( | ||
2229 | "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ", | ||
2230 | client.Name, packet.Type), | ||
2231 | e); | ||
2232 | } | ||
2233 | finally | ||
2234 | { | ||
2235 | m_currentIncomingClient = null; | ||
2236 | } | ||
2237 | } | 2226 | } |
2238 | else | 2227 | finally |
2239 | { | 2228 | { |
2240 | m_log.DebugFormat( | 2229 | m_currentIncomingClient = null; |
2241 | "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", | ||
2242 | packet.Type, client.Name, Scene.RegionInfo.RegionName); | ||
2243 | } | 2230 | } |
2244 | 2231 | ||
2245 | IncomingPacketsProcessed++; | 2232 | IncomingPacketsProcessed++; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs index ac6c0b4..012a57d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs | |||
@@ -48,11 +48,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
48 | 48 | ||
49 | public void Register() | 49 | public void Register() |
50 | { | 50 | { |
51 | /* | ||
51 | m_console.Commands.AddCommand( | 52 | m_console.Commands.AddCommand( |
52 | "Comms", false, "show server throttles", | 53 | "Comms", false, "show server throttles", |
53 | "show server throttles", | 54 | "show server throttles", |
54 | "Show information about server throttles", | 55 | "Show information about server throttles", |
55 | HandleShowServerThrottlesCommand); | 56 | HandleShowServerThrottlesCommand); |
56 | 57 | ||
57 | m_console.Commands.AddCommand( | 58 | m_console.Commands.AddCommand( |
58 | "Debug", false, "debug lludp packet", | 59 | "Debug", false, "debug lludp packet", |
@@ -206,13 +207,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
206 | HandleClientGetCommand); | 207 | HandleClientGetCommand); |
207 | 208 | ||
208 | m_console.Commands.AddCommand( | 209 | m_console.Commands.AddCommand( |
209 | "Debug", | 210 | "Debug", |
210 | false, | 211 | false, |
211 | "debug lludp client set", | 212 | "debug lludp client set", |
212 | "debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]", | 213 | "debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]", |
213 | "Set a debug parameter for a particular client. If no name is given then the value is set on all clients.", | 214 | "Set a debug parameter for a particular client. If no name is given then the value is set on all clients.", |
214 | "process-unacked-sends - Do we take action if a sent reliable packet has not been acked.", | 215 | "process-unacked-sends - Do we take action if a sent reliable packet has not been acked.", |
215 | HandleClientSetCommand); | 216 | HandleClientSetCommand); |
217 | */ | ||
216 | } | 218 | } |
217 | 219 | ||
218 | private void HandleShowServerThrottlesCommand(string module, string[] args) | 220 | private void HandleShowServerThrottlesCommand(string module, string[] args) |
@@ -224,24 +226,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
224 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | 226 | ConsoleDisplayList cdl = new ConsoleDisplayList(); |
225 | cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled); | 227 | cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled); |
226 | 228 | ||
227 | long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate; | 229 | long maxSceneDripRate = (long)m_udpServer.Throttle.MaxDripRate; |
228 | cdl.AddRow( | 230 | cdl.AddRow( |
229 | "Max scene throttle", | 231 | "Max scene throttle", |
230 | maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); | 232 | maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); |
231 | 233 | ||
232 | int maxClientDripRate = m_udpServer.ThrottleRates.Total; | 234 | int maxClientDripRate = m_udpServer.ThrottleRates.Total; |
233 | cdl.AddRow( | 235 | cdl.AddRow( |
234 | "Max new client throttle", | 236 | "Max new client throttle", |
235 | maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset"); | 237 | maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset"); |
236 | 238 | ||
237 | m_console.Output(cdl.ToString()); | 239 | m_console.Output(cdl.ToString()); |
238 | 240 | ||
239 | m_console.OutputFormat("{0}\n", GetServerThrottlesReport(m_udpServer)); | 241 | m_console.OutputFormat("{0}\n", GetServerThrottlesReport(m_udpServer)); |
240 | } | 242 | } |
241 | 243 | ||
242 | private string GetServerThrottlesReport(LLUDPServer udpServer) | 244 | private string GetServerThrottlesReport(LLUDPServer udpServer) |
243 | { | 245 | { |
244 | StringBuilder report = new StringBuilder(); | 246 | StringBuilder report = new StringBuilder(); |
245 | 247 | ||
246 | report.AppendFormat( | 248 | report.AppendFormat( |
247 | "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n", | 249 | "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n", |
@@ -252,7 +254,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
252 | "Cloud", | 254 | "Cloud", |
253 | "Task", | 255 | "Task", |
254 | "Texture", | 256 | "Texture", |
255 | "Asset"); | 257 | "Asset"); |
256 | 258 | ||
257 | report.AppendFormat( | 259 | report.AppendFormat( |
258 | "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n", | 260 | "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n", |
@@ -263,7 +265,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
263 | "kb/s", | 265 | "kb/s", |
264 | "kb/s", | 266 | "kb/s", |
265 | "kb/s", | 267 | "kb/s", |
266 | "kb/s"); | 268 | "kb/s"); |
267 | 269 | ||
268 | ThrottleRates throttleRates = udpServer.ThrottleRates; | 270 | ThrottleRates throttleRates = udpServer.ThrottleRates; |
269 | report.AppendFormat( | 271 | report.AppendFormat( |
@@ -275,16 +277,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
275 | (throttleRates.Cloud * 8) / 1000, | 277 | (throttleRates.Cloud * 8) / 1000, |
276 | (throttleRates.Task * 8) / 1000, | 278 | (throttleRates.Task * 8) / 1000, |
277 | (throttleRates.Texture * 8) / 1000, | 279 | (throttleRates.Texture * 8) / 1000, |
278 | (throttleRates.Asset * 8) / 1000); | 280 | (throttleRates.Asset * 8) / 1000); |
279 | 281 | ||
280 | return report.ToString(); | 282 | return report.ToString(); |
281 | } | 283 | } |
282 | 284 | ||
283 | protected string GetColumnEntry(string entry, int maxLength, int columnPadding) | 285 | protected string GetColumnEntry(string entry, int maxLength, int columnPadding) |
284 | { | 286 | { |
285 | return string.Format( | 287 | return string.Format( |
286 | "{0,-" + maxLength + "}{1,-" + columnPadding + "}", | 288 | "{0,-" + maxLength + "}{1,-" + columnPadding + "}", |
287 | entry.Length > maxLength ? entry.Substring(0, maxLength) : entry, | 289 | entry.Length > maxLength ? entry.Substring(0, maxLength) : entry, |
288 | ""); | 290 | ""); |
289 | } | 291 | } |
290 | 292 | ||
@@ -373,7 +375,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
373 | MainConsole.Instance.OutputFormat( | 375 | MainConsole.Instance.OutputFormat( |
374 | "Usage: debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]"); | 376 | "Usage: debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]"); |
375 | return; | 377 | return; |
376 | } | 378 | } |
377 | 379 | ||
378 | string param = args[4]; | 380 | string param = args[4]; |
379 | string rawValue = args[5]; | 381 | string rawValue = args[5]; |
@@ -465,7 +467,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
465 | MainConsole.Instance.OutputFormat( | 467 | MainConsole.Instance.OutputFormat( |
466 | "Usage: debug lludp throttles get [<avatar-first-name> <avatar-last-name>]"); | 468 | "Usage: debug lludp throttles get [<avatar-first-name> <avatar-last-name>]"); |
467 | return; | 469 | return; |
468 | } | 470 | } |
469 | 471 | ||
470 | string firstName = null; | 472 | string firstName = null; |
471 | string lastName = null; | 473 | string lastName = null; |
@@ -489,7 +491,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
489 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | 491 | ConsoleDisplayList cdl = new ConsoleDisplayList(); |
490 | cdl.AddRow("adaptive", udpClient.FlowThrottle.AdaptiveEnabled); | 492 | cdl.AddRow("adaptive", udpClient.FlowThrottle.AdaptiveEnabled); |
491 | cdl.AddRow("current", string.Format("{0} kbps", udpClient.FlowThrottle.DripRate * 8 / 1000)); | 493 | cdl.AddRow("current", string.Format("{0} kbps", udpClient.FlowThrottle.DripRate * 8 / 1000)); |
492 | cdl.AddRow("request", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000)); | 494 | cdl.AddRow("request", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000)); |
493 | cdl.AddRow("max", string.Format("{0} kbps", udpClient.FlowThrottle.MaxDripRate * 8 / 1000)); | 495 | cdl.AddRow("max", string.Format("{0} kbps", udpClient.FlowThrottle.MaxDripRate * 8 / 1000)); |
494 | 496 | ||
495 | m_console.Output(cdl.ToString()); | 497 | m_console.Output(cdl.ToString()); |
@@ -505,14 +507,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
505 | m_console.OutputFormat("Debug settings for {0}", m_udpServer.Scene.Name); | 507 | m_console.OutputFormat("Debug settings for {0}", m_udpServer.Scene.Name); |
506 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | 508 | ConsoleDisplayList cdl = new ConsoleDisplayList(); |
507 | 509 | ||
508 | long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate; | 510 | long maxSceneDripRate = (long)m_udpServer.Throttle.MaxDripRate; |
509 | cdl.AddRow( | 511 | cdl.AddRow( |
510 | "max-scene-throttle", | 512 | "max-scene-throttle", |
511 | maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); | 513 | maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); |
512 | 514 | ||
513 | int maxClientDripRate = m_udpServer.ThrottleRates.Total; | 515 | int maxClientDripRate = m_udpServer.ThrottleRates.Total; |
514 | cdl.AddRow( | 516 | cdl.AddRow( |
515 | "max-new-client-throttle", | 517 | "max-new-client-throttle", |
516 | maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset"); | 518 | maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset"); |
517 | 519 | ||
518 | m_console.Output(cdl.ToString()); | 520 | m_console.Output(cdl.ToString()); |
@@ -527,7 +529,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
527 | { | 529 | { |
528 | MainConsole.Instance.OutputFormat("Usage: debug lludp set <param> <value>"); | 530 | MainConsole.Instance.OutputFormat("Usage: debug lludp set <param> <value>"); |
529 | return; | 531 | return; |
530 | } | 532 | } |
531 | 533 | ||
532 | string param = args[3]; | 534 | string param = args[3]; |
533 | string rawValue = args[4]; | 535 | string rawValue = args[4]; |
@@ -550,12 +552,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
550 | } | 552 | } |
551 | else | 553 | else |
552 | { | 554 | { |
553 | return; | 555 | return; |
554 | } | 556 | } |
555 | 557 | ||
556 | m_console.OutputFormat("{0} set to {1} in {2}", param, rawValue, m_udpServer.Scene.Name); | 558 | m_console.OutputFormat("{0} set to {1} in {2}", param, rawValue, m_udpServer.Scene.Name); |
557 | } | 559 | } |
558 | 560 | ||
561 | /* not in use, nothing to set/get from lludp | ||
559 | private void HandleClientGetCommand(string module, string[] args) | 562 | private void HandleClientGetCommand(string module, string[] args) |
560 | { | 563 | { |
561 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | 564 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) |
@@ -582,11 +585,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
582 | m_console.OutputFormat( | 585 | m_console.OutputFormat( |
583 | "Client debug parameters for {0} ({1}) in {2}", | 586 | "Client debug parameters for {0} ({1}) in {2}", |
584 | sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name); | 587 | sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name); |
585 | |||
586 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | ||
587 | cdl.AddRow("process-unacked-sends", udpClient.ProcessUnackedSends); | ||
588 | |||
589 | m_console.Output(cdl.ToString()); | ||
590 | } | 588 | } |
591 | }); | 589 | }); |
592 | } | 590 | } |
@@ -600,7 +598,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
600 | { | 598 | { |
601 | MainConsole.Instance.OutputFormat("Usage: debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]"); | 599 | MainConsole.Instance.OutputFormat("Usage: debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]"); |
602 | return; | 600 | return; |
603 | } | 601 | } |
604 | 602 | ||
605 | string param = args[4]; | 603 | string param = args[4]; |
606 | string rawValue = args[5]; | 604 | string rawValue = args[5]; |
@@ -609,28 +607,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
609 | 607 | ||
610 | if (args.Length == 8) | 608 | if (args.Length == 8) |
611 | name = string.Format("{0} {1}", args[6], args[7]); | 609 | name = string.Format("{0} {1}", args[6], args[7]); |
612 | 610 | // nothing here now | |
613 | if (param == "process-unacked-sends") | ||
614 | { | ||
615 | bool newValue; | ||
616 | |||
617 | if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue)) | ||
618 | return; | ||
619 | |||
620 | m_udpServer.Scene.ForEachScenePresence( | ||
621 | sp => | ||
622 | { | ||
623 | if ((name == null || sp.Name == name) && sp.ControllingClient is LLClientView) | ||
624 | { | ||
625 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; | ||
626 | udpClient.ProcessUnackedSends = newValue; | ||
627 | |||
628 | m_console.OutputFormat("{0} set to {1} for {2} in {3}", param, newValue, sp.Name, m_udpServer.Scene.Name); | ||
629 | } | ||
630 | }); | ||
631 | } | ||
632 | } | 611 | } |
633 | 612 | */ | |
634 | private void HandlePacketCommand(string module, string[] args) | 613 | private void HandlePacketCommand(string module, string[] args) |
635 | { | 614 | { |
636 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | 615 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) |
@@ -718,12 +697,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
718 | 697 | ||
719 | string direction = args[3]; | 698 | string direction = args[3]; |
720 | string subCommand = args[4]; | 699 | string subCommand = args[4]; |
721 | string packetName = args[5]; | 700 | string packetName = args[5]; |
722 | 701 | ||
723 | if (subCommand == "add") | 702 | if (subCommand == "add") |
724 | { | 703 | { |
725 | MainConsole.Instance.OutputFormat( | 704 | MainConsole.Instance.OutputFormat( |
726 | "Adding packet {0} to {1} drop list for all connections in {2}", | 705 | "Adding packet {0} to {1} drop list for all connections in {2}", |
727 | direction, packetName, m_udpServer.Scene.Name); | 706 | direction, packetName, m_udpServer.Scene.Name); |
728 | 707 | ||
729 | m_udpServer.Scene.ForEachScenePresence( | 708 | m_udpServer.Scene.ForEachScenePresence( |
@@ -741,7 +720,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
741 | else if (subCommand == "remove") | 720 | else if (subCommand == "remove") |
742 | { | 721 | { |
743 | MainConsole.Instance.OutputFormat( | 722 | MainConsole.Instance.OutputFormat( |
744 | "Removing packet {0} from {1} drop list for all connections in {2}", | 723 | "Removing packet {0} from {1} drop list for all connections in {2}", |
745 | direction, packetName, m_udpServer.Scene.Name); | 724 | direction, packetName, m_udpServer.Scene.Name); |
746 | 725 | ||
747 | m_udpServer.Scene.ForEachScenePresence( | 726 | m_udpServer.Scene.ForEachScenePresence( |
@@ -889,10 +868,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
889 | MainConsole.Instance.OutputFormat("OQRE in {0}", m_udpServer.Scene.Name); | 868 | MainConsole.Instance.OutputFormat("OQRE in {0}", m_udpServer.Scene.Name); |
890 | MainConsole.Instance.OutputFormat("Running: {0}", m_udpServer.OqrEngine.IsRunning); | 869 | MainConsole.Instance.OutputFormat("Running: {0}", m_udpServer.OqrEngine.IsRunning); |
891 | MainConsole.Instance.OutputFormat( | 870 | MainConsole.Instance.OutputFormat( |
892 | "Requests waiting: {0}", | 871 | "Requests waiting: {0}", |
893 | m_udpServer.OqrEngine.IsRunning ? m_udpServer.OqrEngine.JobsWaiting.ToString() : "n/a"); | 872 | m_udpServer.OqrEngine.IsRunning ? m_udpServer.OqrEngine.JobsWaiting.ToString() : "n/a"); |
894 | } | 873 | } |
895 | else | 874 | else |
896 | { | 875 | { |
897 | MainConsole.Instance.OutputFormat("Unrecognized OQRE subcommand {0}", subCommand); | 876 | MainConsole.Instance.OutputFormat("Unrecognized OQRE subcommand {0}", subCommand); |
898 | } | 877 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index f62dc15..f362b06 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |||
@@ -3,25 +3,25 @@ | |||
3 | * Original Author: Jeff Cesnik | 3 | * Original Author: Jeff Cesnik |
4 | * All rights reserved. | 4 | * All rights reserved. |
5 | * | 5 | * |
6 | * - Redistribution and use in source and binary forms, with or without | 6 | * - Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: | 7 | * modification, are permitted provided that the following conditions are met: |
8 | * | 8 | * |
9 | * - Redistributions of source code must retain the above copyright notice, this | 9 | * - Redistributions of source code must retain the above copyright notice, this |
10 | * list of conditions and the following disclaimer. | 10 | * list of conditions and the following disclaimer. |
11 | * - Neither the name of the openmetaverse.org nor the names | 11 | * - Neither the name of the openmetaverse.org nor the names |
12 | * of its contributors may be used to endorse or promote products derived from | 12 | * of its contributors may be used to endorse or promote products derived from |
13 | * this software without specific prior written permission. | 13 | * this software without specific prior written permission. |
14 | * | 14 | * |
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
25 | * POSSIBILITY OF SUCH DAMAGE. | 25 | * POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
@@ -57,9 +57,6 @@ namespace OpenMetaverse | |||
57 | /// <summary>UDP socket, used in either client or server mode</summary> | 57 | /// <summary>UDP socket, used in either client or server mode</summary> |
58 | private Socket m_udpSocket; | 58 | private Socket m_udpSocket; |
59 | 59 | ||
60 | /// <summary>Flag to process packets asynchronously or synchronously</summary> | ||
61 | private bool m_asyncPacketHandling; | ||
62 | |||
63 | /// <summary> | 60 | /// <summary> |
64 | /// Are we to use object pool(s) to reduce memory churn when receiving data? | 61 | /// Are we to use object pool(s) to reduce memory churn when receiving data? |
65 | /// </summary> | 62 | /// </summary> |
@@ -107,13 +104,18 @@ namespace OpenMetaverse | |||
107 | /// </summary> | 104 | /// </summary> |
108 | public float AverageReceiveTicksForLastSamplePeriod { get; private set; } | 105 | public float AverageReceiveTicksForLastSamplePeriod { get; private set; } |
109 | 106 | ||
107 | public int Port | ||
108 | { | ||
109 | get { return m_udpPort; } | ||
110 | } | ||
111 | |||
110 | #region PacketDropDebugging | 112 | #region PacketDropDebugging |
111 | /// <summary> | 113 | /// <summary> |
112 | /// For debugging purposes only... random number generator for dropping | 114 | /// For debugging purposes only... random number generator for dropping |
113 | /// outbound packets. | 115 | /// outbound packets. |
114 | /// </summary> | 116 | /// </summary> |
115 | private Random m_dropRandomGenerator = new Random(); | 117 | private Random m_dropRandomGenerator = new Random(); |
116 | 118 | ||
117 | /// <summary> | 119 | /// <summary> |
118 | /// For debugging purposes only... parameters for a simplified | 120 | /// For debugging purposes only... parameters for a simplified |
119 | /// model of packet loss with bursts, overall drop rate should | 121 | /// model of packet loss with bursts, overall drop rate should |
@@ -132,7 +134,7 @@ namespace OpenMetaverse | |||
132 | /// </summary> | 134 | /// </summary> |
133 | private int m_dropLastTick = 0; | 135 | private int m_dropLastTick = 0; |
134 | private int m_dropResetTicks = 500; | 136 | private int m_dropResetTicks = 500; |
135 | 137 | ||
136 | /// <summary> | 138 | /// <summary> |
137 | /// Debugging code used to simulate dropped packets with bursts | 139 | /// Debugging code used to simulate dropped packets with bursts |
138 | /// </summary> | 140 | /// </summary> |
@@ -179,11 +181,16 @@ namespace OpenMetaverse | |||
179 | // m_dropRandomGenerator = new Random(); | 181 | // m_dropRandomGenerator = new Random(); |
180 | } | 182 | } |
181 | 183 | ||
184 | ~OpenSimUDPBase() | ||
185 | { | ||
186 | if(m_udpSocket !=null) | ||
187 | try { m_udpSocket.Close(); } catch { } | ||
188 | } | ||
182 | /// <summary> | 189 | /// <summary> |
183 | /// Start inbound UDP packet handling. | 190 | /// Start inbound UDP packet handling. |
184 | /// </summary> | 191 | /// </summary> |
185 | /// <param name="recvBufferSize">The size of the receive buffer for | 192 | /// <param name="recvBufferSize">The size of the receive buffer for |
186 | /// the UDP socket. This value is passed up to the operating system | 193 | /// the UDP socket. This value is passed up to the operating system |
187 | /// and used in the system networking stack. Use zero to leave this | 194 | /// and used in the system networking stack. Use zero to leave this |
188 | /// value as the default</param> | 195 | /// value as the default</param> |
189 | /// <param name="asyncPacketHandling">Set this to true to start | 196 | /// <param name="asyncPacketHandling">Set this to true to start |
@@ -195,10 +202,8 @@ namespace OpenMetaverse | |||
195 | /// manner (not throwing an exception when the remote side resets the | 202 | /// manner (not throwing an exception when the remote side resets the |
196 | /// connection). This call is ignored on Mono where the flag is not | 203 | /// connection). This call is ignored on Mono where the flag is not |
197 | /// necessary</remarks> | 204 | /// necessary</remarks> |
198 | public virtual void StartInbound(int recvBufferSize, bool asyncPacketHandling) | 205 | public virtual void StartInbound(int recvBufferSize) |
199 | { | 206 | { |
200 | m_asyncPacketHandling = asyncPacketHandling; | ||
201 | |||
202 | if (!IsRunningInbound) | 207 | if (!IsRunningInbound) |
203 | { | 208 | { |
204 | m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop"); | 209 | m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop"); |
@@ -206,10 +211,6 @@ namespace OpenMetaverse | |||
206 | const int SIO_UDP_CONNRESET = -1744830452; | 211 | const int SIO_UDP_CONNRESET = -1744830452; |
207 | 212 | ||
208 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); | 213 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); |
209 | |||
210 | m_log.DebugFormat( | ||
211 | "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}", | ||
212 | ipep.Address, ipep.Port); | ||
213 | 214 | ||
214 | m_udpSocket = new Socket( | 215 | m_udpSocket = new Socket( |
215 | AddressFamily.InterNetwork, | 216 | AddressFamily.InterNetwork, |
@@ -227,14 +228,23 @@ namespace OpenMetaverse | |||
227 | { | 228 | { |
228 | m_log.Debug("[UDPBASE]: Failed to increase default TTL"); | 229 | m_log.Debug("[UDPBASE]: Failed to increase default TTL"); |
229 | } | 230 | } |
231 | |||
230 | try | 232 | try |
231 | { | 233 | { |
232 | // This udp socket flag is not supported under mono, | 234 | // This udp socket flag is not supported under mono, |
233 | // so we'll catch the exception and continue | 235 | // so we'll catch the exception and continue |
234 | m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); | 236 | // Try does not protect some mono versions on mac |
235 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set"); | 237 | if(Util.IsWindows()) |
238 | { | ||
239 | m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); | ||
240 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set"); | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); | ||
245 | } | ||
236 | } | 246 | } |
237 | catch (SocketException) | 247 | catch |
238 | { | 248 | { |
239 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); | 249 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); |
240 | } | 250 | } |
@@ -243,13 +253,22 @@ namespace OpenMetaverse | |||
243 | // we never want two regions to listen on the same port as they cannot demultiplex each other's messages, | 253 | // we never want two regions to listen on the same port as they cannot demultiplex each other's messages, |
244 | // leading to a confusing bug. | 254 | // leading to a confusing bug. |
245 | // By default, Windows does not allow two sockets to bind to the same port. | 255 | // By default, Windows does not allow two sockets to bind to the same port. |
246 | m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); | 256 | // |
257 | // Unfortunately, this also causes a crashed sim to leave the socket in a state | ||
258 | // where it appears to be in use but is really just hung from the old process | ||
259 | // crashing rather than closing it. While this protects agains misconfiguration, | ||
260 | // allowing crashed sims to be started up again right away, rather than having to | ||
261 | // wait 2 minutes for the socket to clear is more valuable. Commented 12/13/2016 | ||
262 | // m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); | ||
247 | 263 | ||
248 | if (recvBufferSize != 0) | 264 | if (recvBufferSize != 0) |
249 | m_udpSocket.ReceiveBufferSize = recvBufferSize; | 265 | m_udpSocket.ReceiveBufferSize = recvBufferSize; |
250 | 266 | ||
251 | m_udpSocket.Bind(ipep); | 267 | m_udpSocket.Bind(ipep); |
252 | 268 | ||
269 | if (m_udpPort == 0) | ||
270 | m_udpPort = ((IPEndPoint)m_udpSocket.LocalEndPoint).Port; | ||
271 | |||
253 | IsRunningInbound = true; | 272 | IsRunningInbound = true; |
254 | 273 | ||
255 | // kick off an async receive. The Start() method will return, the | 274 | // kick off an async receive. The Start() method will return, the |
@@ -319,7 +338,7 @@ namespace OpenMetaverse | |||
319 | { | 338 | { |
320 | UDPPacketBuffer buf; | 339 | UDPPacketBuffer buf; |
321 | 340 | ||
322 | // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other | 341 | // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other |
323 | // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux. | 342 | // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux. |
324 | // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation. | 343 | // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation. |
325 | // if (UsePools) | 344 | // if (UsePools) |
@@ -372,8 +391,8 @@ namespace OpenMetaverse | |||
372 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); | 391 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); |
373 | } | 392 | } |
374 | } | 393 | } |
375 | catch (ObjectDisposedException e) | 394 | catch (ObjectDisposedException e) |
376 | { | 395 | { |
377 | m_log.Error( | 396 | m_log.Error( |
378 | string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); | 397 | string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); |
379 | } | 398 | } |
@@ -392,12 +411,7 @@ namespace OpenMetaverse | |||
392 | if (IsRunningInbound) | 411 | if (IsRunningInbound) |
393 | { | 412 | { |
394 | UdpReceives++; | 413 | UdpReceives++; |
395 | 414 | ||
396 | // Asynchronous mode will start another receive before the | ||
397 | // callback for this packet is even fired. Very parallel :-) | ||
398 | if (m_asyncPacketHandling) | ||
399 | AsyncBeginReceive(); | ||
400 | |||
401 | try | 415 | try |
402 | { | 416 | { |
403 | // get the buffer that was created in AsyncBeginReceive | 417 | // get the buffer that was created in AsyncBeginReceive |
@@ -419,7 +433,7 @@ namespace OpenMetaverse | |||
419 | // since this should be rare and won't cause a runtime problem. | 433 | // since this should be rare and won't cause a runtime problem. |
420 | if (m_currentReceiveTimeSamples >= s_receiveTimeSamples) | 434 | if (m_currentReceiveTimeSamples >= s_receiveTimeSamples) |
421 | { | 435 | { |
422 | AverageReceiveTicksForLastSamplePeriod | 436 | AverageReceiveTicksForLastSamplePeriod |
423 | = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples; | 437 | = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples; |
424 | 438 | ||
425 | m_receiveTicksInCurrentSamplePeriod = 0; | 439 | m_receiveTicksInCurrentSamplePeriod = 0; |
@@ -431,16 +445,16 @@ namespace OpenMetaverse | |||
431 | m_currentReceiveTimeSamples++; | 445 | m_currentReceiveTimeSamples++; |
432 | } | 446 | } |
433 | } | 447 | } |
434 | catch (SocketException se) | 448 | catch (SocketException se) |
435 | { | 449 | { |
436 | m_log.Error( | 450 | m_log.Error( |
437 | string.Format( | 451 | string.Format( |
438 | "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ", | 452 | "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ", |
439 | UdpReceives, se.ErrorCode), | 453 | UdpReceives, se.ErrorCode), |
440 | se); | 454 | se); |
441 | } | 455 | } |
442 | catch (ObjectDisposedException e) | 456 | catch (ObjectDisposedException e) |
443 | { | 457 | { |
444 | m_log.Error( | 458 | m_log.Error( |
445 | string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e); | 459 | string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e); |
446 | } | 460 | } |
@@ -454,10 +468,7 @@ namespace OpenMetaverse | |||
454 | // if (UsePools) | 468 | // if (UsePools) |
455 | // Pool.ReturnObject(buffer); | 469 | // Pool.ReturnObject(buffer); |
456 | 470 | ||
457 | // Synchronous mode waits until the packet callback completes | 471 | AsyncBeginReceive(); |
458 | // before starting the receive to fetch another packet | ||
459 | if (!m_asyncPacketHandling) | ||
460 | AsyncBeginReceive(); | ||
461 | } | 472 | } |
462 | } | 473 | } |
463 | } | 474 | } |
@@ -471,7 +482,7 @@ namespace OpenMetaverse | |||
471 | // packets when testing throttles & retransmission code | 482 | // packets when testing throttles & retransmission code |
472 | // if (DropOutgoingPacket()) | 483 | // if (DropOutgoingPacket()) |
473 | // return; | 484 | // return; |
474 | 485 | ||
475 | try | 486 | try |
476 | { | 487 | { |
477 | m_udpSocket.BeginSendTo( | 488 | m_udpSocket.BeginSendTo( |
@@ -485,7 +496,7 @@ namespace OpenMetaverse | |||
485 | } | 496 | } |
486 | catch (SocketException) { } | 497 | catch (SocketException) { } |
487 | catch (ObjectDisposedException) { } | 498 | catch (ObjectDisposedException) { } |
488 | // } | 499 | // } |
489 | } | 500 | } |
490 | 501 | ||
491 | void AsyncEndSend(IAsyncResult result) | 502 | void AsyncEndSend(IAsyncResult result) |
@@ -500,5 +511,25 @@ namespace OpenMetaverse | |||
500 | catch (SocketException) { } | 511 | catch (SocketException) { } |
501 | catch (ObjectDisposedException) { } | 512 | catch (ObjectDisposedException) { } |
502 | } | 513 | } |
514 | |||
515 | public void SyncSend(UDPPacketBuffer buf) | ||
516 | { | ||
517 | try | ||
518 | { | ||
519 | m_udpSocket.SendTo( | ||
520 | buf.Data, | ||
521 | 0, | ||
522 | buf.DataLength, | ||
523 | SocketFlags.None, | ||
524 | buf.RemoteEndPoint | ||
525 | ); | ||
526 | UdpSends++; | ||
527 | } | ||
528 | catch (SocketException e) | ||
529 | { | ||
530 | m_log.Warn("[UDPBASE]: sync send SocketException {0} " + e.Message); | ||
531 | } | ||
532 | catch (ObjectDisposedException) { } | ||
533 | } | ||
503 | } | 534 | } |
504 | } \ No newline at end of file | 535 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs index 5a2bcee..f585bea 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs | |||
@@ -62,7 +62,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
62 | /// </summary> | 62 | /// </summary> |
63 | public int PacketsPooled | 63 | public int PacketsPooled |
64 | { | 64 | { |
65 | get | 65 | get |
66 | { | 66 | { |
67 | lock (pool) | 67 | lock (pool) |
68 | return pool.Count; | 68 | return pool.Count; |
@@ -74,9 +74,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
74 | /// </summary> | 74 | /// </summary> |
75 | public int BlocksPooled | 75 | public int BlocksPooled |
76 | { | 76 | { |
77 | get | 77 | get |
78 | { | 78 | { |
79 | lock (DataBlocks) | 79 | lock (DataBlocks) |
80 | return DataBlocks.Count; | 80 | return DataBlocks.Count; |
81 | } | 81 | } |
82 | } | 82 | } |
@@ -248,7 +248,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
248 | } | 248 | } |
249 | } | 249 | } |
250 | break; | 250 | break; |
251 | 251 | ||
252 | // Other packets wont pool | 252 | // Other packets wont pool |
253 | default: | 253 | default: |
254 | return; | 254 | return; |
@@ -276,7 +276,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
276 | { | 276 | { |
277 | DataBlocks[typeof(T)] = new Stack<Object>(); | 277 | DataBlocks[typeof(T)] = new Stack<Object>(); |
278 | } | 278 | } |
279 | 279 | ||
280 | return new T(); | 280 | return new T(); |
281 | } | 281 | } |
282 | } | 282 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs index bf505b4..4a8f16d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs | |||
@@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; | |||
3 | using System.Runtime.InteropServices; | 3 | using System.Runtime.InteropServices; |
4 | using Mono.Addins; | 4 | using Mono.Addins; |
5 | 5 | ||
6 | // General Information about an assembly is controlled through the following | 6 | // General Information about an assembly is controlled through the following |
7 | // set of attributes. Change these attribute values to modify the information | 7 | // set of attributes. Change these attribute values to modify the information |
8 | // associated with an assembly. | 8 | // associated with an assembly. |
9 | [assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenUDP")] | 9 | [assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenUDP")] |
@@ -15,8 +15,8 @@ using Mono.Addins; | |||
15 | [assembly: AssemblyTrademark("")] | 15 | [assembly: AssemblyTrademark("")] |
16 | [assembly: AssemblyCulture("")] | 16 | [assembly: AssemblyCulture("")] |
17 | 17 | ||
18 | // Setting ComVisible to false makes the types in this assembly not visible | 18 | // Setting ComVisible to false makes the types in this assembly not visible |
19 | // to COM components. If you need to access a type in this assembly from | 19 | // to COM components. If you need to access a type in this assembly from |
20 | // COM, set the ComVisible attribute to true on that type. | 20 | // COM, set the ComVisible attribute to true on that type. |
21 | [assembly: ComVisible(false)] | 21 | [assembly: ComVisible(false)] |
22 | 22 | ||
@@ -26,11 +26,11 @@ using Mono.Addins; | |||
26 | // Version information for an assembly consists of the following four values: | 26 | // Version information for an assembly consists of the following four values: |
27 | // | 27 | // |
28 | // Major Version | 28 | // Major Version |
29 | // Minor Version | 29 | // Minor Version |
30 | // Build Number | 30 | // Build Number |
31 | // Revision | 31 | // Revision |
32 | // | 32 | // |
33 | [assembly: AssemblyVersion("0.8.3.*")] | 33 | [assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] |
34 | 34 | ||
35 | [assembly: Addin("LindenUDP", OpenSim.VersionInfo.VersionNumber)] | 35 | [assembly: Addin("LindenUDP", OpenSim.VersionInfo.VersionNumber)] |
36 | [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] | 36 | [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index a935dd2..eb262d2 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs | |||
@@ -70,7 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
70 | m_scene = new SceneHelpers().SetupScene(); | 70 | m_scene = new SceneHelpers().SetupScene(); |
71 | StatsManager.SimExtraStats = new SimExtraStatsCollector(); | 71 | StatsManager.SimExtraStats = new SimExtraStatsCollector(); |
72 | } | 72 | } |
73 | 73 | ||
74 | // /// <summary> | 74 | // /// <summary> |
75 | // /// Build an object name packet for test purposes | 75 | // /// Build an object name packet for test purposes |
76 | // /// </summary> | 76 | // /// </summary> |
@@ -84,13 +84,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
84 | // odb.Name = Utils.StringToBytes(objectName); | 84 | // odb.Name = Utils.StringToBytes(objectName); |
85 | // onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb }; | 85 | // onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb }; |
86 | // onp.Header.Zerocoded = false; | 86 | // onp.Header.Zerocoded = false; |
87 | // | 87 | // |
88 | // return onp; | 88 | // return onp; |
89 | // } | 89 | // } |
90 | // | 90 | // |
91 | /// <summary> | 91 | /// <summary> |
92 | /// Test adding a client to the stack | 92 | /// Test adding a client to the stack |
93 | /// </summary> | 93 | /// </summary> |
94 | /* | ||
94 | [Test] | 95 | [Test] |
95 | public void TestAddClient() | 96 | public void TestAddClient() |
96 | { | 97 | { |
@@ -156,7 +157,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
156 | config.Set("AckTimeout", -1); | 157 | config.Set("AckTimeout", -1); |
157 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics); | 158 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics); |
158 | 159 | ||
159 | ScenePresence sp | 160 | ScenePresence sp |
160 | = ClientStackHelpers.AddChildClient( | 161 | = ClientStackHelpers.AddChildClient( |
161 | m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | 162 | m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); |
162 | 163 | ||
@@ -165,7 +166,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
165 | ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); | 166 | ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); |
166 | Assert.That(spAfterAckTimeout, Is.Null); | 167 | Assert.That(spAfterAckTimeout, Is.Null); |
167 | } | 168 | } |
168 | 169 | */ | |
169 | // /// <summary> | 170 | // /// <summary> |
170 | // /// Test removing a client from the stack | 171 | // /// Test removing a client from the stack |
171 | // /// </summary> | 172 | // /// </summary> |
@@ -175,21 +176,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
175 | // TestHelper.InMethod(); | 176 | // TestHelper.InMethod(); |
176 | // | 177 | // |
177 | // uint myCircuitCode = 123457; | 178 | // uint myCircuitCode = 123457; |
178 | // | 179 | // |
179 | // TestLLUDPServer testLLUDPServer; | 180 | // TestLLUDPServer testLLUDPServer; |
180 | // TestLLPacketServer testLLPacketServer; | 181 | // TestLLPacketServer testLLPacketServer; |
181 | // AgentCircuitManager acm; | 182 | // AgentCircuitManager acm; |
182 | // SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm); | 183 | // SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm); |
183 | // AddClient(myCircuitCode, new IPEndPoint(IPAddress.Loopback, 1000), testLLUDPServer, acm); | 184 | // AddClient(myCircuitCode, new IPEndPoint(IPAddress.Loopback, 1000), testLLUDPServer, acm); |
184 | // | 185 | // |
185 | // testLLUDPServer.RemoveClientCircuit(myCircuitCode); | 186 | // testLLUDPServer.RemoveClientCircuit(myCircuitCode); |
186 | // Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode)); | 187 | // Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode)); |
187 | // | 188 | // |
188 | // // Check that removing a non-existent circuit doesn't have any bad effects | 189 | // // Check that removing a non-existent circuit doesn't have any bad effects |
189 | // testLLUDPServer.RemoveClientCircuit(101); | 190 | // testLLUDPServer.RemoveClientCircuit(101); |
190 | // Assert.IsFalse(testLLUDPServer.HasCircuit(101)); | 191 | // Assert.IsFalse(testLLUDPServer.HasCircuit(101)); |
191 | // } | 192 | // } |
192 | // | 193 | // |
193 | // /// <summary> | 194 | // /// <summary> |
194 | // /// Make sure that the client stack reacts okay to malformed packets | 195 | // /// Make sure that the client stack reacts okay to malformed packets |
195 | // /// </summary> | 196 | // /// </summary> |
@@ -200,8 +201,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
200 | // | 201 | // |
201 | // uint myCircuitCode = 123458; | 202 | // uint myCircuitCode = 123458; |
202 | // EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 1001); | 203 | // EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 1001); |
203 | // MockScene scene = new MockScene(); | 204 | // MockScene scene = new MockScene(); |
204 | // | 205 | // |
205 | // TestLLUDPServer testLLUDPServer; | 206 | // TestLLUDPServer testLLUDPServer; |
206 | // TestLLPacketServer testLLPacketServer; | 207 | // TestLLPacketServer testLLPacketServer; |
207 | // AgentCircuitManager acm; | 208 | // AgentCircuitManager acm; |
@@ -213,24 +214,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
213 | // // Send two garbled 'packets' in succession | 214 | // // Send two garbled 'packets' in succession |
214 | // testLLUDPServer.LoadReceive(data, testEp); | 215 | // testLLUDPServer.LoadReceive(data, testEp); |
215 | // testLLUDPServer.LoadReceive(data, testEp); | 216 | // testLLUDPServer.LoadReceive(data, testEp); |
216 | // testLLUDPServer.ReceiveData(null); | 217 | // testLLUDPServer.ReceiveData(null); |
217 | // | 218 | // |
218 | // // Check that we are still here | 219 | // // Check that we are still here |
219 | // Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode)); | 220 | // Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode)); |
220 | // Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(0)); | 221 | // Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(0)); |
221 | // | 222 | // |
222 | // // Check that sending a valid packet to same circuit still succeeds | 223 | // // Check that sending a valid packet to same circuit still succeeds |
223 | // Assert.That(scene.ObjectNameCallsReceived, Is.EqualTo(0)); | 224 | // Assert.That(scene.ObjectNameCallsReceived, Is.EqualTo(0)); |
224 | // | 225 | // |
225 | // testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "helloooo"), testEp); | 226 | // testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "helloooo"), testEp); |
226 | // testLLUDPServer.ReceiveData(null); | 227 | // testLLUDPServer.ReceiveData(null); |
227 | // | 228 | // |
228 | // Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(1)); | 229 | // Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(1)); |
229 | // Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(1)); | 230 | // Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(1)); |
230 | // } | 231 | // } |
231 | // | 232 | // |
232 | // /// <summary> | 233 | // /// <summary> |
233 | // /// Test that the stack continues to work even if some client has caused a | 234 | // /// Test that the stack continues to work even if some client has caused a |
234 | // /// SocketException on Socket.BeginReceive() | 235 | // /// SocketException on Socket.BeginReceive() |
235 | // /// </summary> | 236 | // /// </summary> |
236 | // [Test] | 237 | // [Test] |
@@ -239,32 +240,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
239 | // TestHelper.InMethod(); | 240 | // TestHelper.InMethod(); |
240 | // | 241 | // |
241 | // MockScene scene = new MockScene(); | 242 | // MockScene scene = new MockScene(); |
242 | // | 243 | // |
243 | // uint circuitCodeA = 130000; | 244 | // uint circuitCodeA = 130000; |
244 | // EndPoint epA = new IPEndPoint(IPAddress.Loopback, 1300); | 245 | // EndPoint epA = new IPEndPoint(IPAddress.Loopback, 1300); |
245 | // UUID agentIdA = UUID.Parse("00000000-0000-0000-0000-000000001300"); | 246 | // UUID agentIdA = UUID.Parse("00000000-0000-0000-0000-000000001300"); |
246 | // UUID sessionIdA = UUID.Parse("00000000-0000-0000-0000-000000002300"); | 247 | // UUID sessionIdA = UUID.Parse("00000000-0000-0000-0000-000000002300"); |
247 | // | 248 | // |
248 | // uint circuitCodeB = 130001; | 249 | // uint circuitCodeB = 130001; |
249 | // EndPoint epB = new IPEndPoint(IPAddress.Loopback, 1301); | 250 | // EndPoint epB = new IPEndPoint(IPAddress.Loopback, 1301); |
250 | // UUID agentIdB = UUID.Parse("00000000-0000-0000-0000-000000001301"); | 251 | // UUID agentIdB = UUID.Parse("00000000-0000-0000-0000-000000001301"); |
251 | // UUID sessionIdB = UUID.Parse("00000000-0000-0000-0000-000000002301"); | 252 | // UUID sessionIdB = UUID.Parse("00000000-0000-0000-0000-000000002301"); |
252 | // | 253 | // |
253 | // TestLLUDPServer testLLUDPServer; | 254 | // TestLLUDPServer testLLUDPServer; |
254 | // TestLLPacketServer testLLPacketServer; | 255 | // TestLLPacketServer testLLPacketServer; |
255 | // AgentCircuitManager acm; | 256 | // AgentCircuitManager acm; |
256 | // SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); | 257 | // SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); |
257 | // AddClient(circuitCodeA, epA, agentIdA, sessionIdA, testLLUDPServer, acm); | 258 | // AddClient(circuitCodeA, epA, agentIdA, sessionIdA, testLLUDPServer, acm); |
258 | // AddClient(circuitCodeB, epB, agentIdB, sessionIdB, testLLUDPServer, acm); | 259 | // AddClient(circuitCodeB, epB, agentIdB, sessionIdB, testLLUDPServer, acm); |
259 | // | 260 | // |
260 | // testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet1"), epA); | 261 | // testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet1"), epA); |
261 | // testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet2"), epB); | 262 | // testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet2"), epB); |
262 | // testLLUDPServer.LoadReceiveWithBeginException(epA); | 263 | // testLLUDPServer.LoadReceiveWithBeginException(epA); |
263 | // testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(2, "packet3"), epB); | 264 | // testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(2, "packet3"), epB); |
264 | // testLLUDPServer.ReceiveData(null); | 265 | // testLLUDPServer.ReceiveData(null); |
265 | // | 266 | // |
266 | // Assert.IsFalse(testLLUDPServer.HasCircuit(circuitCodeA)); | 267 | // Assert.IsFalse(testLLUDPServer.HasCircuit(circuitCodeA)); |
267 | // | 268 | // |
268 | // Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(3)); | 269 | // Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(3)); |
269 | // Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(3)); | 270 | // Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(3)); |
270 | // } | 271 | // } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs index 92f1fc3..1731aa9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs | |||
@@ -59,7 +59,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
59 | // agent.InventoryFolder = UUID.Zero; | 59 | // agent.InventoryFolder = UUID.Zero; |
60 | // agent.startpos = Vector3.Zero; | 60 | // agent.startpos = Vector3.Zero; |
61 | // agent.CapsPath = "http://wibble.com"; | 61 | // agent.CapsPath = "http://wibble.com"; |
62 | // | 62 | // |
63 | // TestLLUDPServer testLLUDPServer; | 63 | // TestLLUDPServer testLLUDPServer; |
64 | // TestLLPacketServer testLLPacketServer; | 64 | // TestLLPacketServer testLLPacketServer; |
65 | // AgentCircuitManager acm; | 65 | // AgentCircuitManager acm; |
@@ -67,7 +67,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
67 | // SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); | 67 | // SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); |
68 | // | 68 | // |
69 | // TestClient testClient = new TestClient(agent, scene); | 69 | // TestClient testClient = new TestClient(agent, scene); |
70 | // | 70 | // |
71 | // LLPacketHandler packetHandler | 71 | // LLPacketHandler packetHandler |
72 | // = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings()); | 72 | // = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings()); |
73 | // | 73 | // |
@@ -87,14 +87,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
87 | // /// <param name="testPacketServer"></param> | 87 | // /// <param name="testPacketServer"></param> |
88 | // /// <param name="acm">Agent circuit manager used in setting up the stack</param> | 88 | // /// <param name="acm">Agent circuit manager used in setting up the stack</param> |
89 | // protected void SetupStack( | 89 | // protected void SetupStack( |
90 | // IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer, | 90 | // IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer, |
91 | // out AgentCircuitManager acm) | 91 | // out AgentCircuitManager acm) |
92 | // { | 92 | // { |
93 | // IConfigSource configSource = new IniConfigSource(); | 93 | // IConfigSource configSource = new IniConfigSource(); |
94 | // ClientStackUserSettings userSettings = new ClientStackUserSettings(); | 94 | // ClientStackUserSettings userSettings = new ClientStackUserSettings(); |
95 | // testLLUDPServer = new TestLLUDPServer(); | 95 | // testLLUDPServer = new TestLLUDPServer(); |
96 | // acm = new AgentCircuitManager(); | 96 | // acm = new AgentCircuitManager(); |
97 | // | 97 | // |
98 | // uint port = 666; | 98 | // uint port = 666; |
99 | // testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm); | 99 | // testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm); |
100 | // testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings); | 100 | // testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs index 3c82a78..873b1e5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs | |||
@@ -35,6 +35,7 @@ using OpenSim.Tests.Common; | |||
35 | 35 | ||
36 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | 36 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests |
37 | { | 37 | { |
38 | /* | ||
38 | [TestFixture] | 39 | [TestFixture] |
39 | public class ThrottleTests : OpenSimTestCase | 40 | public class ThrottleTests : OpenSimTestCase |
40 | { | 41 | { |
@@ -57,16 +58,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
57 | [Test] | 58 | [Test] |
58 | public void TestSetRequestDripRate() | 59 | public void TestSetRequestDripRate() |
59 | { | 60 | { |
61 | |||
60 | TestHelpers.InMethod(); | 62 | TestHelpers.InMethod(); |
61 | 63 | ||
62 | TokenBucket tb = new TokenBucket("tb", null, 5000, 0); | 64 | TokenBucket tb = new TokenBucket(null, 5000f,10000f); |
63 | AssertRates(tb, 5000, 0, 5000, 0); | 65 | AssertRates(tb, 5000, 0, 5000, 0); |
64 | 66 | ||
65 | tb.RequestedDripRate = 4000; | 67 | tb.RequestedDripRate = 4000f; |
66 | AssertRates(tb, 4000, 0, 4000, 0); | 68 | AssertRates(tb, 4000, 0, 4000, 0); |
67 | 69 | ||
68 | tb.RequestedDripRate = 6000; | 70 | tb.RequestedDripRate = 6000; |
69 | AssertRates(tb, 6000, 0, 6000, 0); | 71 | AssertRates(tb, 6000, 0, 6000, 0); |
72 | |||
70 | } | 73 | } |
71 | 74 | ||
72 | [Test] | 75 | [Test] |
@@ -74,7 +77,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
74 | { | 77 | { |
75 | TestHelpers.InMethod(); | 78 | TestHelpers.InMethod(); |
76 | 79 | ||
77 | TokenBucket tb = new TokenBucket("tb", null, 5000, 10000); | 80 | TokenBucket tb = new TokenBucket(null, 5000,15000); |
78 | AssertRates(tb, 5000, 0, 5000, 10000); | 81 | AssertRates(tb, 5000, 0, 5000, 10000); |
79 | 82 | ||
80 | tb.RequestedDripRate = 4000; | 83 | tb.RequestedDripRate = 4000; |
@@ -92,9 +95,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
92 | { | 95 | { |
93 | TestHelpers.InMethod(); | 96 | TestHelpers.InMethod(); |
94 | 97 | ||
95 | TokenBucket tbParent = new TokenBucket("tbParent", null, 0, 0); | 98 | TokenBucket tbParent = new TokenBucket("tbParent", null, 0); |
96 | TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000, 0); | 99 | TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000); |
97 | TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000, 0); | 100 | TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000); |
98 | 101 | ||
99 | AssertRates(tbParent, 8000, 8000, 8000, 0); | 102 | AssertRates(tbParent, 8000, 8000, 8000, 0); |
100 | AssertRates(tbChild1, 3000, 0, 3000, 0); | 103 | AssertRates(tbChild1, 3000, 0, 3000, 0); |
@@ -113,6 +116,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
113 | AssertRates(tbParent, 6000, 8000, 6000, 0); | 116 | AssertRates(tbParent, 6000, 8000, 6000, 0); |
114 | AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0); | 117 | AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0); |
115 | AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0); | 118 | AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0); |
119 | |||
116 | } | 120 | } |
117 | 121 | ||
118 | private void AssertRates( | 122 | private void AssertRates( |
@@ -133,7 +137,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
133 | Scene scene = new SceneHelpers().SetupScene(); | 137 | Scene scene = new SceneHelpers().SetupScene(); |
134 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); | 138 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); |
135 | 139 | ||
136 | ScenePresence sp | 140 | ScenePresence sp |
137 | = ClientStackHelpers.AddChildClient( | 141 | = ClientStackHelpers.AddChildClient( |
138 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | 142 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); |
139 | 143 | ||
@@ -141,7 +145,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
141 | 145 | ||
142 | udpServer.Throttle.DebugLevel = 1; | 146 | udpServer.Throttle.DebugLevel = 1; |
143 | udpClient.ThrottleDebugLevel = 1; | 147 | udpClient.ThrottleDebugLevel = 1; |
144 | 148 | ||
145 | int resendBytes = 1000; | 149 | int resendBytes = 1000; |
146 | int landBytes = 2000; | 150 | int landBytes = 2000; |
147 | int windBytes = 3000; | 151 | int windBytes = 3000; |
@@ -157,8 +161,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
157 | int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes; | 161 | int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes; |
158 | 162 | ||
159 | AssertThrottles( | 163 | AssertThrottles( |
160 | udpClient, | 164 | udpClient, |
161 | LLUDPServer.MTU, landBytes, windBytes, cloudBytes, taskBytes, | 165 | LLUDPServer.MTU, landBytes, windBytes, cloudBytes, taskBytes, |
162 | textureBytes, assetBytes, totalBytes, 0, 0); | 166 | textureBytes, assetBytes, totalBytes, 0, 0); |
163 | } | 167 | } |
164 | 168 | ||
@@ -177,7 +181,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
177 | 181 | ||
178 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics); | 182 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics); |
179 | 183 | ||
180 | ScenePresence sp | 184 | ScenePresence sp |
181 | = ClientStackHelpers.AddChildClient( | 185 | = ClientStackHelpers.AddChildClient( |
182 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | 186 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); |
183 | 187 | ||
@@ -203,7 +207,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
203 | double commitRatio = 32000.0 / totalBytes; | 207 | double commitRatio = 32000.0 / totalBytes; |
204 | 208 | ||
205 | AssertThrottles( | 209 | AssertThrottles( |
206 | udpClient, | 210 | udpClient, |
207 | LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, | 211 | LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, |
208 | textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); | 212 | textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); |
209 | 213 | ||
@@ -213,7 +217,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
213 | commitRatio = (32000.0 + 20.0 * LLUDPServer.MTU) / totalBytes; | 217 | commitRatio = (32000.0 + 20.0 * LLUDPServer.MTU) / totalBytes; |
214 | 218 | ||
215 | AssertThrottles( | 219 | AssertThrottles( |
216 | udpClient, | 220 | udpClient, |
217 | LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, | 221 | LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, |
218 | textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); | 222 | textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); |
219 | 223 | ||
@@ -223,7 +227,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
223 | commitRatio = (32000.0 + (20.0 * LLUDPServer.MTU)/Math.Pow(2,1)) / totalBytes; | 227 | commitRatio = (32000.0 + (20.0 * LLUDPServer.MTU)/Math.Pow(2,1)) / totalBytes; |
224 | 228 | ||
225 | AssertThrottles( | 229 | AssertThrottles( |
226 | udpClient, | 230 | udpClient, |
227 | LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, | 231 | LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, |
228 | textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); | 232 | textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); |
229 | } | 233 | } |
@@ -244,14 +248,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
244 | int taskBytes = 14000; | 248 | int taskBytes = 14000; |
245 | int textureBytes = 16000; | 249 | int textureBytes = 16000; |
246 | int assetBytes = 18000; | 250 | int assetBytes = 18000; |
247 | int totalBytes | 251 | int totalBytes |
248 | = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2); | 252 | = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2); |
249 | 253 | ||
250 | Scene scene = new SceneHelpers().SetupScene(); | 254 | Scene scene = new SceneHelpers().SetupScene(); |
251 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); | 255 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); |
252 | udpServer.Throttle.RequestedDripRate = totalBytes; | 256 | udpServer.Throttle.RequestedDripRate = totalBytes; |
253 | 257 | ||
254 | ScenePresence sp1 | 258 | ScenePresence sp1 |
255 | = ClientStackHelpers.AddChildClient( | 259 | = ClientStackHelpers.AddChildClient( |
256 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | 260 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); |
257 | 261 | ||
@@ -261,8 +265,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
261 | udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | 265 | udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); |
262 | 266 | ||
263 | AssertThrottles( | 267 | AssertThrottles( |
264 | udpClient1, | 268 | udpClient1, |
265 | resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2, | 269 | resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2, |
266 | textureBytes / 2, assetBytes / 2, totalBytes, 0, 0); | 270 | textureBytes / 2, assetBytes / 2, totalBytes, 0, 0); |
267 | 271 | ||
268 | // Test: Now add another client | 272 | // Test: Now add another client |
@@ -277,13 +281,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
277 | udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | 281 | udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); |
278 | 282 | ||
279 | AssertThrottles( | 283 | AssertThrottles( |
280 | udpClient1, | 284 | udpClient1, |
281 | resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4, | 285 | resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4, |
282 | textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0); | 286 | textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0); |
283 | 287 | ||
284 | AssertThrottles( | 288 | AssertThrottles( |
285 | udpClient2, | 289 | udpClient2, |
286 | resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4, | 290 | resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4, |
287 | textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0); | 291 | textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0); |
288 | } | 292 | } |
289 | 293 | ||
@@ -303,14 +307,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
303 | int taskBytes = 12000; | 307 | int taskBytes = 12000; |
304 | int textureBytes = 14000; | 308 | int textureBytes = 14000; |
305 | int assetBytes = 16000; | 309 | int assetBytes = 16000; |
306 | int totalBytes | 310 | int totalBytes |
307 | = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2); | 311 | = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2); |
308 | 312 | ||
309 | Scene scene = new SceneHelpers().SetupScene(); | 313 | Scene scene = new SceneHelpers().SetupScene(); |
310 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); | 314 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); |
311 | udpServer.ThrottleRates.Total = totalBytes; | 315 | udpServer.ThrottleRates.Total = totalBytes; |
312 | 316 | ||
313 | ScenePresence sp | 317 | ScenePresence sp |
314 | = ClientStackHelpers.AddChildClient( | 318 | = ClientStackHelpers.AddChildClient( |
315 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | 319 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); |
316 | 320 | ||
@@ -321,8 +325,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
321 | udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | 325 | udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); |
322 | 326 | ||
323 | AssertThrottles( | 327 | AssertThrottles( |
324 | udpClient, | 328 | udpClient, |
325 | resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2, | 329 | resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2, |
326 | textureBytes / 2, assetBytes / 2, totalBytes, 0, totalBytes); | 330 | textureBytes / 2, assetBytes / 2, totalBytes, 0, totalBytes); |
327 | } | 331 | } |
328 | 332 | ||
@@ -348,7 +352,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
348 | udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1); | 352 | udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1); |
349 | udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5); | 353 | udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5); |
350 | 354 | ||
351 | ScenePresence sp1 | 355 | ScenePresence sp1 |
352 | = ClientStackHelpers.AddChildClient( | 356 | = ClientStackHelpers.AddChildClient( |
353 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | 357 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); |
354 | 358 | ||
@@ -359,8 +363,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
359 | udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | 363 | udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); |
360 | 364 | ||
361 | AssertThrottles( | 365 | AssertThrottles( |
362 | udpClient1, | 366 | udpClient1, |
363 | resendBytes, landBytes, windBytes, cloudBytes, taskBytes, | 367 | resendBytes, landBytes, windBytes, cloudBytes, taskBytes, |
364 | textureBytes, assetBytes, totalBytes, 0, totalBytes * 1.1); | 368 | textureBytes, assetBytes, totalBytes, 0, totalBytes * 1.1); |
365 | 369 | ||
366 | // Now add another client | 370 | // Now add another client |
@@ -375,25 +379,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
375 | udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | 379 | udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); |
376 | 380 | ||
377 | AssertThrottles( | 381 | AssertThrottles( |
378 | udpClient1, | 382 | udpClient1, |
379 | resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75, | 383 | resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75, |
380 | textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1); | 384 | textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1); |
381 | 385 | ||
382 | AssertThrottles( | 386 | AssertThrottles( |
383 | udpClient2, | 387 | udpClient2, |
384 | resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75, | 388 | resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75, |
385 | textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1); | 389 | textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1); |
386 | } | 390 | } |
387 | 391 | ||
388 | private void AssertThrottles( | 392 | private void AssertThrottles( |
389 | LLUDPClient udpClient, | 393 | LLUDPClient udpClient, |
390 | double resendBytes, double landBytes, double windBytes, double cloudBytes, double taskBytes, double textureBytes, double assetBytes, | 394 | double resendBytes, double landBytes, double windBytes, double cloudBytes, double taskBytes, double textureBytes, double assetBytes, |
391 | double totalBytes, double targetBytes, double maxBytes) | 395 | double totalBytes, double targetBytes, double maxBytes) |
392 | { | 396 | { |
393 | ClientInfo ci = udpClient.GetClientInfo(); | 397 | ClientInfo ci = udpClient.GetClientInfo(); |
394 | 398 | ||
395 | // Console.WriteLine( | 399 | // Console.WriteLine( |
396 | // "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}", | 400 | // "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}", |
397 | // ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle); | 401 | // ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle); |
398 | 402 | ||
399 | Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend"); | 403 | Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend"); |
@@ -424,4 +428,5 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
424 | udpClient.SetThrottles(throttles); | 428 | udpClient.SetThrottles(throttles); |
425 | } | 429 | } |
426 | } | 430 | } |
431 | */ | ||
427 | } \ No newline at end of file | 432 | } \ No newline at end of file |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs index 7a2756b..f8ec97a 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs | |||
@@ -58,17 +58,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
58 | 58 | ||
59 | /// <summary>Flag used to enable adaptive throttles</summary> | 59 | /// <summary>Flag used to enable adaptive throttles</summary> |
60 | public bool AdaptiveThrottlesEnabled; | 60 | public bool AdaptiveThrottlesEnabled; |
61 | 61 | ||
62 | /// <summary> | 62 | /// <summary> |
63 | /// Set the minimum rate that the adaptive throttles can set. The viewer | 63 | /// Set the minimum rate that the adaptive throttles can set. The viewer |
64 | /// can still throttle lower than this, but the adaptive throttles will | 64 | /// can still throttle lower than this, but the adaptive throttles will |
65 | /// never decrease rates below this no matter how many packets are dropped | 65 | /// never decrease rates below this no matter how many packets are dropped |
66 | /// </summary> | 66 | /// </summary> |
67 | public Int64 MinimumAdaptiveThrottleRate; | 67 | public Int64 MinimumAdaptiveThrottleRate; |
68 | 68 | ||
69 | /// <summary>Amount of the texture throttle to steal for the task throttle</summary> | 69 | /// <summary>Amount of the texture throttle to steal for the task throttle</summary> |
70 | public double CannibalizeTextureRate; | 70 | public double CannibalizeTextureRate; |
71 | 71 | ||
72 | public int ClientMaxRate; | ||
73 | public float BrustTime; | ||
74 | |||
72 | /// <summary> | 75 | /// <summary> |
73 | /// Default constructor | 76 | /// Default constructor |
74 | /// </summary> | 77 | /// </summary> |
@@ -88,13 +91,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
88 | Texture = throttleConfig.GetInt("texture_default", 18500); | 91 | Texture = throttleConfig.GetInt("texture_default", 18500); |
89 | Asset = throttleConfig.GetInt("asset_default", 10500); | 92 | Asset = throttleConfig.GetInt("asset_default", 10500); |
90 | 93 | ||
91 | Total = throttleConfig.GetInt("client_throttle_max_bps", 0); | 94 | Total = Resend + Land + Wind + Cloud + Task + Texture + Asset; |
95 | // 5120000 bps default max | ||
96 | ClientMaxRate = throttleConfig.GetInt("client_throttle_max_bps", 640000); | ||
97 | if (ClientMaxRate > 1000000) | ||
98 | ClientMaxRate = 1000000; // no more than 8Mbps | ||
92 | 99 | ||
93 | AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); | 100 | BrustTime = (float)throttleConfig.GetInt("client_throttle_burtsTimeMS", 10); |
101 | BrustTime *= 1e-3f; | ||
102 | |||
103 | // Adaptive is broken | ||
104 | // AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); | ||
105 | AdaptiveThrottlesEnabled = false; | ||
94 | MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000); | 106 | MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000); |
95 | 107 | ||
96 | CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f); | 108 | // http textures do use udp bandwidth setting |
97 | CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9); | 109 | // CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f); |
110 | // CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9); | ||
111 | CannibalizeTextureRate = 0f; | ||
112 | |||
98 | } | 113 | } |
99 | catch (Exception) { } | 114 | catch (Exception) { } |
100 | } | 115 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index 4616203..1daf091 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs | |||
@@ -43,150 +43,143 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
43 | { | 43 | { |
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | 45 | ||
46 | public string Identifier { get; private set; } | 46 | private static Int32 m_counter = 0; |
47 | 47 | ||
48 | public int DebugLevel { get; set; } | 48 | // private Int32 m_identifier; |
49 | 49 | ||
50 | /// <summary> | 50 | protected const float m_timeScale = 1e-3f; |
51 | /// Number of ticks (ms) per quantum, drip rate and max burst | ||
52 | /// are defined over this interval. | ||
53 | /// </summary> | ||
54 | protected const Int32 m_ticksPerQuantum = 1000; | ||
55 | 51 | ||
56 | /// <summary> | 52 | /// <summary> |
57 | /// This is the number of quantums worth of packets that can | 53 | /// This is the number of m_minimumDripRate bytes |
58 | /// be accommodated during a burst | 54 | /// allowed in a burst |
55 | /// roughtly, with this settings, the maximum time system will take | ||
56 | /// to recheck a bucket in ms | ||
57 | /// | ||
59 | /// </summary> | 58 | /// </summary> |
60 | protected const Double m_quantumsPerBurst = 1.5; | 59 | protected const float m_quantumsPerBurst = 5; |
61 | 60 | ||
62 | /// <summary> | 61 | /// <summary> |
63 | /// </summary> | 62 | /// </summary> |
64 | protected const Int32 m_minimumDripRate = LLUDPServer.MTU; | 63 | protected const float m_minimumDripRate = 1500; |
65 | 64 | ||
66 | /// <summary>Time of the last drip, in system ticks</summary> | 65 | /// <summary>Time of the last drip</summary> |
67 | protected Int32 m_lastDrip; | 66 | protected double m_lastDrip; |
68 | 67 | ||
69 | /// <summary> | 68 | /// <summary> |
70 | /// The number of bytes that can be sent at this moment. This is the | 69 | /// The number of bytes that can be sent at this moment. This is the |
71 | /// current number of tokens in the bucket | 70 | /// current number of tokens in the bucket |
72 | /// </summary> | 71 | /// </summary> |
73 | protected Int64 m_tokenCount; | 72 | protected float m_tokenCount; |
74 | 73 | ||
75 | /// <summary> | 74 | /// <summary> |
76 | /// Map of children buckets and their requested maximum burst rate | 75 | /// Map of children buckets and their requested maximum burst rate |
77 | /// </summary> | 76 | /// </summary> |
78 | protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); | 77 | |
78 | protected Dictionary<TokenBucket, float> m_children = new Dictionary<TokenBucket, float>(); | ||
79 | |||
80 | #region Properties | ||
79 | 81 | ||
80 | /// <summary> | 82 | /// <summary> |
81 | /// The parent bucket of this bucket, or null if this bucket has no | 83 | /// The parent bucket of this bucket, or null if this bucket has no |
82 | /// parent. The parent bucket will limit the aggregate bandwidth of all | 84 | /// parent. The parent bucket will limit the aggregate bandwidth of all |
83 | /// of its children buckets | 85 | /// of its children buckets |
84 | /// </summary> | 86 | /// </summary> |
85 | public TokenBucket Parent { get; protected set; } | 87 | protected TokenBucket m_parent; |
86 | 88 | public TokenBucket Parent | |
89 | { | ||
90 | get { return m_parent; } | ||
91 | set { m_parent = value; } | ||
92 | } | ||
87 | /// <summary> | 93 | /// <summary> |
88 | /// Maximum burst rate in bytes per second. This is the maximum number | 94 | /// This is the maximum number |
89 | /// of tokens that can accumulate in the bucket at any one time. This | 95 | /// of tokens that can accumulate in the bucket at any one time. This |
90 | /// also sets the total request for leaf nodes | 96 | /// also sets the total request for leaf nodes |
91 | /// </summary> | 97 | /// </summary> |
92 | protected Int64 m_burstRate; | 98 | protected float m_burst; |
93 | public Int64 RequestedBurstRate | 99 | |
100 | protected float m_maxDripRate = 0; | ||
101 | public virtual float MaxDripRate | ||
94 | { | 102 | { |
95 | get { return m_burstRate; } | 103 | get { return m_maxDripRate; } |
96 | set { m_burstRate = (value < 0 ? 0 : value); } | 104 | set { m_maxDripRate = value; } |
97 | } | 105 | } |
98 | 106 | ||
99 | public Int64 BurstRate | 107 | public float RequestedBurst |
100 | { | 108 | { |
101 | get { | 109 | get { return m_burst; } |
102 | double rate = RequestedBurstRate * BurstRateModifier(); | 110 | set { |
103 | if (rate < m_minimumDripRate * m_quantumsPerBurst) | 111 | float rate = (value < 0 ? 0 : value); |
112 | if (rate < 1.5f * m_minimumDripRate) | ||
113 | rate = 1.5f * m_minimumDripRate; | ||
114 | else if (rate > m_minimumDripRate * m_quantumsPerBurst) | ||
104 | rate = m_minimumDripRate * m_quantumsPerBurst; | 115 | rate = m_minimumDripRate * m_quantumsPerBurst; |
105 | 116 | ||
106 | return (Int64) rate; | 117 | m_burst = rate; |
118 | } | ||
119 | } | ||
120 | |||
121 | public float Burst | ||
122 | { | ||
123 | get { | ||
124 | float rate = RequestedBurst * BurstModifier(); | ||
125 | if (rate < m_minimumDripRate) | ||
126 | rate = m_minimumDripRate; | ||
127 | return (float)rate; | ||
107 | } | 128 | } |
108 | } | 129 | } |
109 | 130 | ||
110 | /// <summary> | 131 | /// <summary> |
111 | /// The requested drip rate for this particular bucket. | 132 | /// The requested drip rate for this particular bucket. |
112 | /// </summary> | 133 | /// </summary> |
113 | /// <remarks> | 134 | /// <remarks> |
114 | /// 0 then TotalDripRequest is used instead. | 135 | /// 0 then TotalDripRequest is used instead. |
115 | /// Can never be above MaxDripRate. | 136 | /// Can never be above MaxDripRate. |
116 | /// Tokens are added to the bucket at any time | 137 | /// Tokens are added to the bucket at any time |
117 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of | 138 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of |
118 | /// the system tick interval (typically around 15-22ms) | 139 | /// the system tick interval (typically around 15-22ms)</remarks> |
119 | /// FIXME: It is extremely confusing to be able to set a RequestedDripRate of 0 and then receive a positive | 140 | protected float m_dripRate; |
120 | /// number on get if TotalDripRequest is set. This also stops us being able to retrieve the fact that | ||
121 | /// RequestedDripRate is set to 0. Really, this should always return m_dripRate and then we can get | ||
122 | /// (m_dripRate == 0 ? TotalDripRequest : m_dripRate) on some other properties. | ||
123 | /// </remarks> | ||
124 | public virtual Int64 RequestedDripRate | ||
125 | { | ||
126 | get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); } | ||
127 | set | ||
128 | { | ||
129 | if (value <= 0) | ||
130 | m_dripRate = 0; | ||
131 | else if (MaxDripRate > 0 && value > MaxDripRate) | ||
132 | m_dripRate = MaxDripRate; | ||
133 | else | ||
134 | m_dripRate = value; | ||
135 | 141 | ||
136 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); | 142 | public float RequestedDripRate |
143 | { | ||
144 | get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } | ||
145 | set { | ||
146 | m_dripRate = (value < 0 ? 0 : value); | ||
147 | m_totalDripRequest = m_dripRate; | ||
137 | 148 | ||
138 | if (Parent != null) | 149 | if (m_parent != null) |
139 | Parent.RegisterRequest(this, m_dripRate); | 150 | m_parent.RegisterRequest(this,m_dripRate); |
140 | } | 151 | } |
141 | } | 152 | } |
142 | 153 | ||
143 | /// <summary> | 154 | public float DripRate |
144 | /// Gets the drip rate. | ||
145 | /// </summary> | ||
146 | /// <value> | ||
147 | /// DripRate can never be above max drip rate or below min drip rate. | ||
148 | /// If we are a child bucket then the drip rate return is modifed by the total load on the capacity of the | ||
149 | /// parent bucket. | ||
150 | /// </value> | ||
151 | public virtual Int64 DripRate | ||
152 | { | 155 | { |
153 | get | 156 | get { |
154 | { | 157 | float rate = Math.Min(RequestedDripRate,TotalDripRequest); |
155 | double rate; | 158 | if (m_parent == null) |
156 | 159 | return rate; | |
157 | // FIXME: This doesn't properly work if we have a parent and children and a requested drip rate set | ||
158 | // on ourselves which is not equal to the child drip rates. | ||
159 | if (Parent == null) | ||
160 | { | ||
161 | if (TotalDripRequest > 0) | ||
162 | rate = Math.Min(RequestedDripRate, TotalDripRequest); | ||
163 | else | ||
164 | rate = RequestedDripRate; | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | rate = (double)RequestedDripRate * Parent.DripRateModifier(); | ||
169 | } | ||
170 | 160 | ||
161 | rate *= m_parent.DripRateModifier(); | ||
171 | if (rate < m_minimumDripRate) | 162 | if (rate < m_minimumDripRate) |
172 | rate = m_minimumDripRate; | 163 | rate = m_minimumDripRate; |
173 | else if (MaxDripRate > 0 && rate > MaxDripRate) | ||
174 | rate = MaxDripRate; | ||
175 | 164 | ||
176 | return (Int64)rate; | 165 | return (float)rate; |
177 | } | 166 | } |
178 | } | 167 | } |
179 | protected Int64 m_dripRate; | ||
180 | |||
181 | // <summary> | ||
182 | // The maximum rate for flow control. Drip rate can never be greater than this. | ||
183 | // </summary> | ||
184 | public Int64 MaxDripRate { get; set; } | ||
185 | 168 | ||
186 | /// <summary> | 169 | /// <summary> |
187 | /// The current total of the requested maximum burst rates of children buckets. | 170 | /// The current total of the requested maximum burst rates of children buckets. |
188 | /// </summary> | 171 | /// </summary> |
189 | public Int64 TotalDripRequest { get; protected set; } | 172 | protected float m_totalDripRequest; |
173 | public float TotalDripRequest | ||
174 | { | ||
175 | get { return m_totalDripRequest; } | ||
176 | set { m_totalDripRequest = value; } | ||
177 | } | ||
178 | |||
179 | #endregion Properties | ||
180 | |||
181 | #region Constructor | ||
182 | |||
190 | 183 | ||
191 | /// <summary> | 184 | /// <summary> |
192 | /// Default constructor | 185 | /// Default constructor |
@@ -194,20 +187,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
194 | /// <param name="identifier">Identifier for this token bucket</param> | 187 | /// <param name="identifier">Identifier for this token bucket</param> |
195 | /// <param name="parent">Parent bucket if this is a child bucket, or | 188 | /// <param name="parent">Parent bucket if this is a child bucket, or |
196 | /// null if this is a root bucket</param> | 189 | /// null if this is a root bucket</param> |
197 | /// <param name="requestedDripRate"> | 190 | /// <param name="maxBurst">Maximum size of the bucket in bytes, or |
198 | /// Requested rate that the bucket fills, in bytes per | 191 | /// zero if this bucket has no maximum capacity</param> |
199 | /// second. If zero, the bucket always remains full. | 192 | /// <param name="dripRate">Rate that the bucket fills, in bytes per |
200 | /// </param> | 193 | /// second. If zero, the bucket always remains full</param> |
201 | public TokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate) | 194 | public TokenBucket(TokenBucket parent, float dripRate, float MaxBurst) |
202 | { | 195 | { |
203 | Identifier = identifier; | 196 | m_counter++; |
204 | 197 | ||
205 | Parent = parent; | 198 | Parent = parent; |
206 | RequestedDripRate = requestedDripRate; | 199 | RequestedDripRate = dripRate; |
207 | MaxDripRate = maxDripRate; | 200 | RequestedBurst = MaxBurst; |
208 | m_lastDrip = Util.EnvironmentTickCount(); | 201 | m_lastDrip = Util.GetTimeStampMS() + 100000.0; // skip first drip |
209 | } | 202 | } |
210 | 203 | ||
204 | #endregion Constructor | ||
205 | |||
211 | /// <summary> | 206 | /// <summary> |
212 | /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning | 207 | /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning |
213 | /// no modification if the requested bandwidth is less than the | 208 | /// no modification if the requested bandwidth is less than the |
@@ -215,22 +210,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
215 | /// hierarchy. However, if any of the parents is over-booked, then | 210 | /// hierarchy. However, if any of the parents is over-booked, then |
216 | /// the modifier will be less than 1. | 211 | /// the modifier will be less than 1. |
217 | /// </summary> | 212 | /// </summary> |
218 | protected double DripRateModifier() | 213 | protected float DripRateModifier() |
219 | { | 214 | { |
220 | Int64 driprate = DripRate; | 215 | float driprate = DripRate; |
221 | double modifier = driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; | 216 | return driprate >= TotalDripRequest ? 1.0f : (driprate / TotalDripRequest); |
222 | |||
223 | // if (DebugLevel > 0) | ||
224 | // m_log.DebugFormat( | ||
225 | // "[TOKEN BUCKET]: Returning drip modifier {0}/{1} = {2} from {3}", | ||
226 | // driprate, TotalDripRequest, modifier, Identifier); | ||
227 | |||
228 | return modifier; | ||
229 | } | 217 | } |
230 | 218 | ||
231 | /// <summary> | 219 | /// <summary> |
232 | /// </summary> | 220 | /// </summary> |
233 | protected double BurstRateModifier() | 221 | protected float BurstModifier() |
234 | { | 222 | { |
235 | // for now... burst rate is always m_quantumsPerBurst (constant) | 223 | // for now... burst rate is always m_quantumsPerBurst (constant) |
236 | // larger than drip rate so the ratio of burst requests is the | 224 | // larger than drip rate so the ratio of burst requests is the |
@@ -242,29 +230,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
242 | /// Register drip rate requested by a child of this throttle. Pass the | 230 | /// Register drip rate requested by a child of this throttle. Pass the |
243 | /// changes up the hierarchy. | 231 | /// changes up the hierarchy. |
244 | /// </summary> | 232 | /// </summary> |
245 | public void RegisterRequest(TokenBucket child, Int64 request) | 233 | public void RegisterRequest(TokenBucket child, float request) |
246 | { | 234 | { |
247 | lock (m_children) | 235 | lock (m_children) |
248 | { | 236 | { |
249 | m_children[child] = request; | 237 | m_children[child] = request; |
250 | 238 | ||
251 | TotalDripRequest = 0; | 239 | m_totalDripRequest = 0; |
252 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | 240 | foreach (KeyValuePair<TokenBucket, float> cref in m_children) |
253 | TotalDripRequest += cref.Value; | 241 | m_totalDripRequest += cref.Value; |
254 | } | 242 | } |
255 | |||
256 | // Pass the new values up to the parent | ||
257 | if (Parent != null) | ||
258 | { | ||
259 | Int64 effectiveDripRate; | ||
260 | |||
261 | if (RequestedDripRate > 0) | ||
262 | effectiveDripRate = Math.Min(RequestedDripRate, TotalDripRequest); | ||
263 | else | ||
264 | effectiveDripRate = TotalDripRequest; | ||
265 | 243 | ||
266 | Parent.RegisterRequest(this, effectiveDripRate); | 244 | // Pass the new values up to the parent |
267 | } | 245 | if (m_parent != null) |
246 | m_parent.RegisterRequest(this, Math.Min(RequestedDripRate, TotalDripRequest)); | ||
268 | } | 247 | } |
269 | 248 | ||
270 | /// <summary> | 249 | /// <summary> |
@@ -277,23 +256,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
277 | { | 256 | { |
278 | m_children.Remove(child); | 257 | m_children.Remove(child); |
279 | 258 | ||
280 | TotalDripRequest = 0; | 259 | m_totalDripRequest = 0; |
281 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | 260 | foreach (KeyValuePair<TokenBucket, float> cref in m_children) |
282 | TotalDripRequest += cref.Value; | 261 | m_totalDripRequest += cref.Value; |
283 | } | 262 | } |
284 | 263 | ||
285 | // Pass the new values up to the parent | 264 | // Pass the new values up to the parent |
286 | if (Parent != null) | 265 | if (Parent != null) |
287 | Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); | 266 | Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); |
288 | } | 267 | } |
289 | 268 | ||
290 | /// <summary> | 269 | /// <summary> |
291 | /// Remove a given number of tokens from the bucket | 270 | /// Remove a given number of tokens from the bucket |
292 | /// </summary> | 271 | /// </summary> |
293 | /// <param name="amount">Number of tokens to remove from the bucket</param> | 272 | /// <param name="amount">Number of tokens to remove from the bucket</param> |
294 | /// <returns>True if the requested number of tokens were removed from | 273 | /// <returns>True if the requested number of tokens were removed from |
295 | /// the bucket, otherwise false</returns> | 274 | /// the bucket, otherwise false</returns> |
296 | public bool RemoveTokens(Int64 amount) | 275 | public bool RemoveTokens(int amount) |
297 | { | 276 | { |
298 | // Deposit tokens for this interval | 277 | // Deposit tokens for this interval |
299 | Drip(); | 278 | Drip(); |
@@ -310,24 +289,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
310 | return false; | 289 | return false; |
311 | } | 290 | } |
312 | 291 | ||
313 | /// <summary> | 292 | public bool CheckTokens(int amount) |
314 | /// Deposit tokens into the bucket from a child bucket that did | ||
315 | /// not use all of its available tokens | ||
316 | /// </summary> | ||
317 | protected void Deposit(Int64 count) | ||
318 | { | 293 | { |
319 | m_tokenCount += count; | 294 | return (m_tokenCount - amount >= 0); |
295 | } | ||
320 | 296 | ||
321 | // Deposit the overflow in the parent bucket, this is how we share | 297 | public int GetCatBytesCanSend(int timeMS) |
322 | // unused bandwidth | 298 | { |
323 | Int64 burstrate = BurstRate; | 299 | // return (int)(m_tokenCount + timeMS * m_dripRate * 1e-3); |
324 | if (m_tokenCount > burstrate) | 300 | return (int)(timeMS * DripRate * 1e-3); |
325 | m_tokenCount = burstrate; | ||
326 | } | 301 | } |
327 | 302 | ||
328 | /// <summary> | 303 | /// <summary> |
329 | /// Add tokens to the bucket over time. The number of tokens added each | 304 | /// Add tokens to the bucket over time. The number of tokens added each |
330 | /// call depends on the length of time that has passed since the last | 305 | /// call depends on the length of time that has passed since the last |
331 | /// call to Drip | 306 | /// call to Drip |
332 | /// </summary> | 307 | /// </summary> |
333 | /// <returns>True if tokens were added to the bucket, otherwise false</returns> | 308 | /// <returns>True if tokens were added to the bucket, otherwise false</returns> |
@@ -337,128 +312,106 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
337 | // with no drip rate... | 312 | // with no drip rate... |
338 | if (DripRate == 0) | 313 | if (DripRate == 0) |
339 | { | 314 | { |
340 | m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", Identifier); | 315 | m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", m_counter); |
341 | return; | 316 | return; |
342 | } | 317 | } |
343 | 318 | ||
344 | // Determine the interval over which we are adding tokens, never add | 319 | double now = Util.GetTimeStampMS(); |
345 | // more than a single quantum of tokens | 320 | double deltaMS = now - m_lastDrip; |
346 | Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum); | 321 | m_lastDrip = now; |
347 | m_lastDrip = Util.EnvironmentTickCount(); | 322 | |
348 | |||
349 | // This can be 0 in the very unusual case that the timer wrapped | ||
350 | // It can be 0 if we try add tokens at a sub-tick rate | ||
351 | if (deltaMS <= 0) | 323 | if (deltaMS <= 0) |
352 | return; | 324 | return; |
353 | 325 | ||
354 | Deposit(deltaMS * DripRate / m_ticksPerQuantum); | 326 | m_tokenCount += (float)deltaMS * DripRate * m_timeScale; |
327 | |||
328 | float burst = Burst; | ||
329 | if (m_tokenCount > burst) | ||
330 | m_tokenCount = burst; | ||
355 | } | 331 | } |
356 | } | 332 | } |
357 | 333 | ||
358 | public class AdaptiveTokenBucket : TokenBucket | 334 | public class AdaptiveTokenBucket : TokenBucket |
359 | { | 335 | { |
360 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 336 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
361 | 337 | ||
362 | public bool AdaptiveEnabled { get; set; } | 338 | public bool AdaptiveEnabled { get; set; } |
363 | 339 | ||
364 | /// <summary> | 340 | /// <summary> |
365 | /// Target drip rate for this bucket. | 341 | /// The minimum rate for flow control. Minimum drip rate is one |
342 | /// packet per second. | ||
366 | /// </summary> | 343 | /// </summary> |
367 | /// <remarks>Usually set by the client. If adaptive is enabled then throttles will increase until we reach this.</remarks> | 344 | |
368 | public Int64 TargetDripRate | 345 | protected const float m_minimumFlow = 50000; |
369 | { | 346 | |
370 | get { return m_targetDripRate; } | 347 | // <summary> |
371 | set | 348 | // The maximum rate for flow control. Drip rate can never be |
349 | // greater than this. | ||
350 | // </summary> | ||
351 | |||
352 | public override float MaxDripRate | ||
353 | { | ||
354 | get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } | ||
355 | set | ||
372 | { | 356 | { |
373 | m_targetDripRate = Math.Max(value, m_minimumFlow); | 357 | m_maxDripRate = (value == 0 ? m_totalDripRequest : Math.Max(value, m_minimumFlow)); |
374 | } | 358 | } |
375 | } | 359 | } |
376 | protected Int64 m_targetDripRate; | 360 | |
361 | private bool m_enabled = false; | ||
377 | 362 | ||
378 | // <summary> | 363 | // <summary> |
379 | // Adjust drip rate in response to network conditions. | 364 | // Adjust drip rate in response to network conditions. |
380 | // </summary> | 365 | // </summary> |
381 | public virtual Int64 AdjustedDripRate | 366 | public float AdjustedDripRate |
382 | { | 367 | { |
383 | get { return m_dripRate; } | 368 | get { return m_dripRate; } |
384 | set | 369 | set |
385 | { | 370 | { |
386 | m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate); | 371 | m_dripRate = OpenSim.Framework.Util.Clamp<float>(value, m_minimumFlow, MaxDripRate); |
387 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); | ||
388 | 372 | ||
389 | if (Parent != null) | 373 | if (m_parent != null) |
390 | Parent.RegisterRequest(this, m_dripRate); | 374 | m_parent.RegisterRequest(this, m_dripRate); |
391 | } | 375 | } |
392 | } | 376 | } |
393 | |||
394 | /// <summary> | ||
395 | /// The minimum rate for adaptive flow control. | ||
396 | /// </summary> | ||
397 | protected Int64 m_minimumFlow = 32000; | ||
398 | 377 | ||
399 | /// <summary> | ||
400 | /// Constructor for the AdaptiveTokenBucket class | ||
401 | /// <param name="identifier">Unique identifier for the client</param> | ||
402 | /// <param name="parent">Parent bucket in the hierarchy</param> | ||
403 | /// <param name="requestedDripRate"></param> | ||
404 | /// <param name="maxDripRate">The ceiling rate for adaptation</param> | ||
405 | /// <param name="minDripRate">The floor rate for adaptation</param> | ||
406 | /// </summary> | ||
407 | public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate, Int64 minDripRate, bool enabled) | ||
408 | : base(identifier, parent, requestedDripRate, maxDripRate) | ||
409 | { | ||
410 | AdaptiveEnabled = enabled; | ||
411 | 378 | ||
412 | if (AdaptiveEnabled) | 379 | // <summary> |
413 | { | 380 | // |
414 | // m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled"); | 381 | // </summary> |
415 | m_minimumFlow = minDripRate; | 382 | public AdaptiveTokenBucket(TokenBucket parent, float maxDripRate, float maxBurst, bool enabled) |
416 | TargetDripRate = m_minimumFlow; | 383 | : base(parent, maxDripRate, maxBurst) |
417 | AdjustedDripRate = m_minimumFlow; | ||
418 | } | ||
419 | } | ||
420 | |||
421 | /// <summary> | ||
422 | /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down. | ||
423 | /// <param name="packets">Number of packets that expired without successful delivery</param> | ||
424 | /// </summary> | ||
425 | public void ExpirePackets(Int32 packets) | ||
426 | { | 384 | { |
427 | if (AdaptiveEnabled) | 385 | m_enabled = enabled; |
428 | { | ||
429 | if (DebugLevel > 0) | ||
430 | m_log.WarnFormat( | ||
431 | "[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}", | ||
432 | AdjustedDripRate, packets, Identifier); | ||
433 | 386 | ||
434 | // AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,packets)); | 387 | m_maxDripRate = (maxDripRate == 0 ? m_totalDripRequest : Math.Max(maxDripRate, m_minimumFlow)); |
435 | 388 | ||
436 | // Compute the fallback solely on the rate allocated beyond the minimum, this | 389 | if (enabled) |
437 | // should smooth out the fallback to the minimum rate | 390 | m_dripRate = m_maxDripRate * .5f; |
438 | AdjustedDripRate = m_minimumFlow + (Int64) ((AdjustedDripRate - m_minimumFlow) / Math.Pow(2, packets)); | 391 | else |
439 | } | 392 | m_dripRate = m_maxDripRate; |
393 | if (m_parent != null) | ||
394 | m_parent.RegisterRequest(this, m_dripRate); | ||
440 | } | 395 | } |
441 | 396 | ||
442 | /// <summary> | 397 | /// <summary> |
443 | /// Reliable packets acked by the client adjust the drip rate up. | 398 | /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down. |
444 | /// <param name="packets">Number of packets successfully acknowledged</param> | 399 | /// <param name="packets">Number of packets that expired without successful delivery</param> |
445 | /// </summary> | 400 | /// </summary> |
446 | public void AcknowledgePackets(Int32 packets) | 401 | public void ExpirePackets(Int32 count) |
447 | { | 402 | { |
448 | if (AdaptiveEnabled) | 403 | // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count); |
449 | AdjustedDripRate = AdjustedDripRate + packets * LLUDPServer.MTU; | 404 | if (m_enabled) |
405 | AdjustedDripRate = (Int64)(AdjustedDripRate / Math.Pow(2, count)); | ||
450 | } | 406 | } |
451 | 407 | ||
452 | /// <summary> | 408 | // <summary> |
453 | /// Adjust the minimum flow level for the adaptive throttle, this will drop adjusted | 409 | // |
454 | /// throttles back to the minimum levels | 410 | // </summary> |
455 | /// <param>minDripRate--the new minimum flow</param> | 411 | public void AcknowledgePackets(Int32 count) |
456 | /// </summary> | ||
457 | public void ResetMinimumAdaptiveFlow(Int64 minDripRate) | ||
458 | { | 412 | { |
459 | m_minimumFlow = minDripRate; | 413 | if (m_enabled) |
460 | TargetDripRate = m_minimumFlow; | 414 | AdjustedDripRate = AdjustedDripRate + count; |
461 | AdjustedDripRate = m_minimumFlow; | ||
462 | } | 415 | } |
463 | } | 416 | } |
464 | } \ No newline at end of file | 417 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs index b546a99..76f4c6f 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs | |||
@@ -74,6 +74,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
74 | /// <summary>Holds information about pending removals</summary> | 74 | /// <summary>Holds information about pending removals</summary> |
75 | private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>(); | 75 | private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>(); |
76 | 76 | ||
77 | |||
78 | public void Clear() | ||
79 | { | ||
80 | m_packets.Clear(); | ||
81 | m_pendingAdds = null; | ||
82 | m_pendingAcknowledgements = null; | ||
83 | m_pendingRemoves = null; | ||
84 | } | ||
85 | |||
77 | /// <summary> | 86 | /// <summary> |
78 | /// Add an unacked packet to the collection | 87 | /// Add an unacked packet to the collection |
79 | /// </summary> | 88 | /// </summary> |
@@ -85,7 +94,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
85 | public void Add(OutgoingPacket packet) | 94 | public void Add(OutgoingPacket packet) |
86 | { | 95 | { |
87 | m_pendingAdds.Enqueue(packet); | 96 | m_pendingAdds.Enqueue(packet); |
88 | Interlocked.Add(ref packet.Client.UnackedBytes, packet.Buffer.DataLength); | 97 | Interlocked.Add(ref packet.Client.UnackedBytes, packet.Buffer.DataLength); |
89 | } | 98 | } |
90 | 99 | ||
91 | /// <summary> | 100 | /// <summary> |
@@ -107,7 +116,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
107 | /// <summary> | 116 | /// <summary> |
108 | /// Marks a packet as no longer needing acknowledgement without a received acknowledgement. | 117 | /// Marks a packet as no longer needing acknowledgement without a received acknowledgement. |
109 | /// This method is called when a packet expires and we no longer need an acknowledgement. | 118 | /// This method is called when a packet expires and we no longer need an acknowledgement. |
110 | /// When some reliable packet types expire, they are handled in a way other than simply | 119 | /// When some reliable packet types expire, they are handled in a way other than simply |
111 | /// resending them. The only effect of removal this way is to update unacked byte count. | 120 | /// resending them. The only effect of removal this way is to update unacked byte count. |
112 | /// </summary> | 121 | /// </summary> |
113 | /// <param name="sequenceNumber">Sequence number of the packet to | 122 | /// <param name="sequenceNumber">Sequence number of the packet to |
@@ -146,7 +155,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
146 | 155 | ||
147 | foreach (OutgoingPacket packet in m_packets.Values) | 156 | foreach (OutgoingPacket packet in m_packets.Values) |
148 | { | 157 | { |
149 | // TickCount of zero means a packet is in the resend queue | 158 | // TickCount of zero means a packet is in the resend queue |
150 | // but hasn't actually been sent over the wire yet | 159 | // but hasn't actually been sent over the wire yet |
151 | if (packet.TickCount == 0) | 160 | if (packet.TickCount == 0) |
152 | continue; | 161 | continue; |
@@ -163,7 +172,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
163 | // As with other network applications, assume that an expired packet is | 172 | // As with other network applications, assume that an expired packet is |
164 | // an indication of some network problem, slow transmission | 173 | // an indication of some network problem, slow transmission |
165 | packet.Client.FlowThrottle.ExpirePackets(1); | 174 | packet.Client.FlowThrottle.ExpirePackets(1); |
166 | 175 | ||
167 | expiredPackets.Add(packet); | 176 | expiredPackets.Add(packet); |
168 | } | 177 | } |
169 | } | 178 | } |
@@ -182,7 +191,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
182 | while (m_pendingAdds.TryDequeue(out pendingAdd)) | 191 | while (m_pendingAdds.TryDequeue(out pendingAdd)) |
183 | if (pendingAdd != null) | 192 | if (pendingAdd != null) |
184 | m_packets[pendingAdd.SequenceNumber] = pendingAdd; | 193 | m_packets[pendingAdd.SequenceNumber] = pendingAdd; |
185 | 194 | ||
186 | // Process all the pending removes, including updating statistics and round-trip times | 195 | // Process all the pending removes, including updating statistics and round-trip times |
187 | PendingAck pendingAcknowledgement; | 196 | PendingAck pendingAcknowledgement; |
188 | while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement)) | 197 | while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement)) |
@@ -219,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
219 | else | 228 | else |
220 | { | 229 | { |
221 | // m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack", | 230 | // m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack", |
222 | // pendingAcknowledgement.SequenceNumber); | 231 | // pendingAcknowledgement.SequenceNumber); |
223 | } | 232 | } |
224 | } | 233 | } |
225 | 234 | ||
diff --git a/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs index 0b6ee2f..e859653 100644 --- a/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs | |||
@@ -2,7 +2,7 @@ | |||
2 | using System.Runtime.CompilerServices; | 2 | using System.Runtime.CompilerServices; |
3 | using System.Runtime.InteropServices; | 3 | using System.Runtime.InteropServices; |
4 | 4 | ||
5 | // General Information about an assembly is controlled through the following | 5 | // General Information about an assembly is controlled through the following |
6 | // set of attributes. Change these attribute values to modify the information | 6 | // set of attributes. Change these attribute values to modify the information |
7 | // associated with an assembly. | 7 | // associated with an assembly. |
8 | [assembly: AssemblyTitle("OpenSim.Region.ClientStack")] | 8 | [assembly: AssemblyTitle("OpenSim.Region.ClientStack")] |
@@ -14,8 +14,8 @@ using System.Runtime.InteropServices; | |||
14 | [assembly: AssemblyTrademark("")] | 14 | [assembly: AssemblyTrademark("")] |
15 | [assembly: AssemblyCulture("")] | 15 | [assembly: AssemblyCulture("")] |
16 | 16 | ||
17 | // Setting ComVisible to false makes the types in this assembly not visible | 17 | // Setting ComVisible to false makes the types in this assembly not visible |
18 | // to COM components. If you need to access a type in this assembly from | 18 | // to COM components. If you need to access a type in this assembly from |
19 | // COM, set the ComVisible attribute to true on that type. | 19 | // COM, set the ComVisible attribute to true on that type. |
20 | [assembly: ComVisible(false)] | 20 | [assembly: ComVisible(false)] |
21 | 21 | ||
@@ -25,7 +25,7 @@ using System.Runtime.InteropServices; | |||
25 | // Version information for an assembly consists of the following four values: | 25 | // Version information for an assembly consists of the following four values: |
26 | // | 26 | // |
27 | // Major Version | 27 | // Major Version |
28 | // Minor Version | 28 | // Minor Version |
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |